commit
commit
6e2cd9fe2a
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
|
||||
VITE_COMMON_API_PREFIX = /api
|
||||
|
||||
VITE_COMMON_API_URL = http://store-manage.hmily.club
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
VITE_COMMON_API_PREFIX = /api
|
||||
|
||||
VITE_COMMON_API_URL = http://store-manage.hmily.club
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
VITE_COMMON_API_PREFIX = /api
|
||||
|
||||
VITE_COMMON_API_URL = http://store-manage.hmily.club
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"name": "uni-preset-vue",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev:app": "uni -p app",
|
||||
"dev:app-android": "uni -p app-android",
|
||||
"dev:app-ios": "uni -p app-ios",
|
||||
"dev:custom": "uni -p",
|
||||
"dev:h5": "uni",
|
||||
"dev:h5:ssr": "uni --ssr",
|
||||
"dev:mp-alipay": "uni -p mp-alipay",
|
||||
"dev:mp-baidu": "uni -p mp-baidu",
|
||||
"dev:mp-jd": "uni -p mp-jd",
|
||||
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||
"dev:mp-lark": "uni -p mp-lark",
|
||||
"dev:mp-qq": "uni -p mp-qq",
|
||||
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||
"dev:mp-weixin": "uni -p mp-weixin",
|
||||
"dev:mp-xhs": "uni -p mp-xhs",
|
||||
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||
"build:app": "uni build -p app",
|
||||
"build:app-android": "uni build -p app-android",
|
||||
"build:app-ios": "uni build -p app-ios",
|
||||
"build:custom": "uni build -p",
|
||||
"build:h5": "uni build",
|
||||
"build:h5:ssr": "uni build --ssr",
|
||||
"build:mp-alipay": "uni build -p mp-alipay",
|
||||
"build:mp-baidu": "uni build -p mp-baidu",
|
||||
"build:mp-jd": "uni build -p mp-jd",
|
||||
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||
"build:mp-lark": "uni build -p mp-lark",
|
||||
"build:mp-qq": "uni build -p mp-qq",
|
||||
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||
"build:mp-weixin": "uni build -p mp-weixin",
|
||||
"build:mp-xhs": "uni build -p mp-xhs",
|
||||
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
|
||||
},
|
||||
"dependencies": {
|
||||
"@climblee/uv-ui": "^1.1.20",
|
||||
"@dcloudio/uni-app": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-app-plus": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-components": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-h5": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-alipay": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-baidu": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-jd": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-kuaishou": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-lark": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-qq": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-mp-xhs": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-3090920231225001",
|
||||
"@qiun/ucharts": "^2.5.0-20230101",
|
||||
"luch-request": "^3.1.1",
|
||||
"pinia": "2.0.33",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.3.2",
|
||||
"@dcloudio/uni-automator": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-3090920231225001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-3090920231225001",
|
||||
"@vue/runtime-core": "^3.2.45",
|
||||
"sass": "^1.71.1",
|
||||
"unocss": "^0.58.5",
|
||||
"unocss-applet": "^0.7.8",
|
||||
"vite": "4.0.3"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference types='@dcloudio/types' />
|
||||
import 'vue'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
type Hooks = App.AppInstance & Page.PageInstance;
|
||||
|
||||
interface ComponentCustomOptions extends Hooks {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<script>
|
||||
// import { useUserStoreWithOut } from "@/store/modules/user";
|
||||
export default {
|
||||
onLaunch: function () {
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: function () {
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function () {
|
||||
console.log('App Hide')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/static/css/index.scss';
|
||||
@import '@climblee/uv-ui/index.scss';
|
||||
</style>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<view
|
||||
class="flex items-center h-92rpx pl-base pr-15rpx rounded-19rpx bg-white"
|
||||
:class="[{ 'card-shadow': shadow }]"
|
||||
@click="$emit('onClick')"
|
||||
>
|
||||
<view
|
||||
class="text-[#333333] font-400 text-27rpx"
|
||||
:style="[
|
||||
{ width: `${getPx(titleWidth)}px`, fontSize: `${getPx(textSize)}px` },
|
||||
]"
|
||||
>{{ title }}</view
|
||||
>
|
||||
<view class="flex-1">
|
||||
<slot></slot>
|
||||
</view>
|
||||
<view class="h-full flex-center">
|
||||
<slot name="right-icon">
|
||||
<image
|
||||
v-if="isLink"
|
||||
class="w-26rpx h-26rpx"
|
||||
src="@/static/images/me_icon_more_def.svg"
|
||||
></image>
|
||||
</slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { getPx } from '@climblee/uv-ui/libs/function/index.js'
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
isLink: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
shadow: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
titleWidth: {
|
||||
type: String,
|
||||
default: '1130rpx',
|
||||
},
|
||||
textSize: {
|
||||
type: String,
|
||||
default: '27rpx',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<template>
|
||||
<uv-navbar
|
||||
:fixed="fixed"
|
||||
:bgColor="bgColor"
|
||||
:leftIcon="leftIcon"
|
||||
:title="title"
|
||||
:titleStyle="{...titleStyle}"
|
||||
:placeholder="placeholder"
|
||||
@leftClick="onLeftClick"
|
||||
z-index="1000"
|
||||
>
|
||||
<template #left>
|
||||
<slot name="left">
|
||||
<image
|
||||
v-if="isBack && !leftIcon"
|
||||
class="w-54rpx h-54rpx"
|
||||
src="/static/images/icon_back_def.svg"
|
||||
></image>
|
||||
</slot>
|
||||
</template>
|
||||
<template #center>
|
||||
<slot name="center"></slot>
|
||||
</template>
|
||||
|
||||
<template #right>
|
||||
<view :style="[{ paddingRight: addUnit(paddingRight) }]">
|
||||
<slot name="right"></slot>
|
||||
</view>
|
||||
</template>
|
||||
</uv-navbar>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
let menuButtonInfo = {}
|
||||
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
|
||||
menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
||||
// #endif
|
||||
|
||||
import { computed } from 'vue'
|
||||
import { addUnit, sys } from '@climblee/uv-ui/libs/function/index.js'
|
||||
|
||||
const props = defineProps({
|
||||
fixed: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isBack: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
autoBack: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
placeholder: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: '#ee2c37',
|
||||
},
|
||||
imgMode: {
|
||||
type: String,
|
||||
default: 'aspectFill',
|
||||
},
|
||||
safeAreaInsetTop: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: '44px',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
leftIcon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
titleStyle: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
color: '#fff',
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['leftClick'])
|
||||
|
||||
const paddingRight = computed(() => {
|
||||
let rightButtonWidth = 0
|
||||
rightButtonWidth =
|
||||
sys().windowWidth - (menuButtonInfo?.left ?? sys().windowWidth)
|
||||
return `${rightButtonWidth}px`
|
||||
})
|
||||
const onLeftClick = () => {
|
||||
emit('leftClick')
|
||||
if (props.autoBack) {
|
||||
// #ifdef H5
|
||||
let canNavBack = getCurrentPages()
|
||||
if (canNavBack && canNavBack.length > 1) {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
} else {
|
||||
history.back()
|
||||
}
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.navigateBack()
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<view>
|
||||
<view class="flex justify-end text-white" @click="onClick">
|
||||
<view>{{ valueFormat }}</view>
|
||||
<uv-icon color="white" size="16rpx" name="arrow-down-fill"></uv-icon>
|
||||
</view>
|
||||
<uv-datetime-picker
|
||||
ref="datetimePicker"
|
||||
v-model="value"
|
||||
:mode="mode"
|
||||
@confirm="confirm"
|
||||
:maxDate="Number(new Date())"
|
||||
:minDate="Number(new Date(2020, 0, 1))"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, watch, watchEffect, computed } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: null,
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'year-month',
|
||||
},
|
||||
formatStr: {
|
||||
type: String,
|
||||
default: 'yyyy年mm月',
|
||||
},
|
||||
})
|
||||
const datetimePicker = ref(null)
|
||||
const value = ref(props.modelValue || Number(new Date()))
|
||||
const valueFormat = computed(() => {
|
||||
return timeFormat(value.value, props.formatStr)
|
||||
})
|
||||
|
||||
|
||||
const emit = defineEmits(['update:modelValue','confirm'])
|
||||
|
||||
|
||||
const confirm = (e) => {
|
||||
value.value = e.value
|
||||
emit('confirm', e)
|
||||
}
|
||||
|
||||
const onClick = () => {
|
||||
datetimePicker.value.open()
|
||||
}
|
||||
|
||||
|
||||
watchEffect(() => {
|
||||
value.value = props.modelValue || Number(new Date())
|
||||
})
|
||||
|
||||
watch(
|
||||
() => value.value,
|
||||
(val) => {
|
||||
emit('update:modelValue', val)
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
<template>
|
||||
<!-- 不能用v-if (i: 每个tab页的专属下标; index: 当前tab的下标 )-->
|
||||
<view v-show="i === index">
|
||||
<!-- top="120"下拉布局往下偏移,防止被悬浮菜单遮住 -->
|
||||
<mescroll-body
|
||||
:height="`${scrollHeight}px`"
|
||||
@init="mescrollInit"
|
||||
:down="downOption"
|
||||
@down="downCallback"
|
||||
:up="upOption"
|
||||
@up="upCallback"
|
||||
|
||||
>
|
||||
<slot :list="list"></slot>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { http } from '@/utils/request'
|
||||
import { sys } from '@climblee/uv-ui/libs/function'
|
||||
import { ref, watch, nextTick, computed } from 'vue'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
// import { apiGoods } from '@/api/mock.js'
|
||||
|
||||
const props = defineProps({
|
||||
i: Number,
|
||||
index: {
|
||||
type: Number,
|
||||
default() {
|
||||
return 0
|
||||
},
|
||||
},
|
||||
top: {
|
||||
type: Number,
|
||||
default: 44,
|
||||
},
|
||||
apiUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
const scrollHeight = computed(() => {
|
||||
return sys().screenHeight - props.top
|
||||
})
|
||||
|
||||
// 子组件的mescroll-body无需传入onPageScroll, onReachBottom
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll() // 调用mescroll的hook
|
||||
|
||||
defineExpose({ getMescroll }) // 使父组件可以通过ref调用到getMescroll方法 (必须)
|
||||
|
||||
const isAutoInit = props.i === props.index // 自动加载当前tab的数据
|
||||
const downOption = {
|
||||
auto: isAutoInit, // 自动加载当前tab的数据
|
||||
}
|
||||
|
||||
const upOption = {
|
||||
auto: false, // 不自动加载
|
||||
noMoreSize: 4, //如果列表已无数据,可设置列表的总数量要大于半页才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看; 默认5
|
||||
empty: {
|
||||
tip: '~ 空空如也 ~', // 提示
|
||||
},
|
||||
}
|
||||
|
||||
const isInit = ref(isAutoInit) // 当前tab是否已初始化
|
||||
const list = ref([]) // 数据列表
|
||||
|
||||
// 监听下标的变化
|
||||
watch(
|
||||
() => props.index,
|
||||
(val) => {
|
||||
if (props.i === val && !isInit.value) mescrollTrigger()
|
||||
}
|
||||
)
|
||||
|
||||
// 主动触发加载
|
||||
const mescrollTrigger = () => {
|
||||
isInit.value = true // 标记为true
|
||||
const mescroll = getMescroll()
|
||||
if (mescroll) {
|
||||
if (mescroll.optDown.use) {
|
||||
mescroll.triggerDownScroll()
|
||||
} else {
|
||||
mescroll.triggerUpScroll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*上拉加载的回调: 其中mescroll.num:当前页 从1开始, mescroll.size:每页数据条数,默认10 */
|
||||
const upCallback = async (mescroll) => {
|
||||
await nextTick()
|
||||
if (!props.apiUrl) return
|
||||
http.request({
|
||||
url: props.apiUrl,
|
||||
method: 'GET',
|
||||
params: {
|
||||
per_page: mescroll.size,
|
||||
page: mescroll.num,
|
||||
...props.params,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
const arr = res.data || [] // 当前页数据
|
||||
if (mescroll.num == 1) list.value = [] //如果是第一页需手动制空列表
|
||||
list.value = list.value.concat(arr) //追加新数据
|
||||
mescroll.endSuccess(arr.length) // 请求成功, 结束加载
|
||||
})
|
||||
.catch(() => {
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
})
|
||||
// let word = props.tabs[props.i].name // 具体项目中,您可能取的是tab中的type,status等字段
|
||||
// apiGoods(mescroll.num, mescroll.size, word)
|
||||
// .then((res) => {
|
||||
// const list = res.list || [] // 当前页数据
|
||||
// if (mescroll.num == 1) goods.value = [] //如果是第一页需手动制空列表
|
||||
// goods.value = goods.value.concat(list) //追加新数据
|
||||
// mescroll.endSuccess(list.length) // 请求成功, 结束加载
|
||||
// })
|
||||
// .catch(() => {
|
||||
// mescroll.endErr() // 请求失败, 结束加载
|
||||
// })
|
||||
}
|
||||
|
||||
//点击空布局按钮的回调
|
||||
const emptyClick = () => {
|
||||
uni.showToast({
|
||||
title: '点击了按钮,具体逻辑自行实现',
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<template>
|
||||
<!-- 当mescroll-body写在子组件时,父页面需引入useMescrollComp.js -->
|
||||
<mescroll-body
|
||||
:height="`${scrollHeight}px`"
|
||||
@init="mescrollInit"
|
||||
@down="downCallback"
|
||||
@up="upCallback"
|
||||
>
|
||||
<slot :list="list"></slot>
|
||||
</mescroll-body>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { sys } from '@climblee/uv-ui/libs/function'
|
||||
import { ref, computed, nextTick } from 'vue'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
import { http } from '@/utils/request'
|
||||
const props = defineProps({
|
||||
top: {
|
||||
type: Number,
|
||||
default: 44,
|
||||
},
|
||||
apiUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
const scrollHeight = computed(() => {
|
||||
return sys().screenHeight - props.top
|
||||
})
|
||||
const list = ref([]) // 数据列表
|
||||
|
||||
// 子组件的mescroll-body无需传入onPageScroll, onReachBottom
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll() // 调用mescroll的hook
|
||||
|
||||
// 使父组件可以通过ref调用到getMescroll方法 (必须)
|
||||
defineExpose({ getMescroll })
|
||||
|
||||
// 上拉加载的回调: 其中num:当前页 从1开始, size:每页数据条数,默认10
|
||||
const upCallback = async (mescroll) => {
|
||||
await nextTick()
|
||||
if (!props.apiUrl) return
|
||||
http
|
||||
.get(props.apiUrl, {
|
||||
params: {
|
||||
per_page: mescroll.size,
|
||||
page: mescroll.num,
|
||||
...props.params,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
const curPageData = res.data || [] // 当前页数据
|
||||
if (mescroll.num == 1) list.value = [] // 第一页需手动制空列表
|
||||
list.value = list.value.concat(curPageData) // 追加新数据
|
||||
mescroll.endSuccess(curPageData.length) // 隐藏加载进度
|
||||
})
|
||||
.catch(() => {
|
||||
mescroll.endErr() // 隐藏加载进度
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="title" :style="{ fontSize: `${getPx(textSize)}px` }">{{
|
||||
title
|
||||
}}</view>
|
||||
<view>
|
||||
<slot name="right"></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { getPx } from '@climblee/uv-ui/libs/function/index.js'
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
textSize: {
|
||||
type: String,
|
||||
default: '27rpx',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.title {
|
||||
@apply relative pl-20rpx;
|
||||
&::after {
|
||||
content: '';
|
||||
@apply absolute left-0 bottom-4rpx top-4rpx w-3px bg-primary;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
export const useGlobSetting = () => {
|
||||
|
||||
const ENV = import.meta.env
|
||||
|
||||
|
||||
const { VITE_COMMON_API_PREFIX, VITE_COMMON_API_URL } = ENV
|
||||
|
||||
let apiUrl = ''
|
||||
// #ifdef MP-WEIXIN || APP-PLUS
|
||||
apiUrl += VITE_COMMON_API_URL
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
apiUrl += VITE_COMMON_API_PREFIX
|
||||
// #endif
|
||||
|
||||
return {
|
||||
urlPrefix: VITE_COMMON_API_PREFIX,
|
||||
api: VITE_COMMON_API_URL,
|
||||
apiUrl: apiUrl
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import {
|
||||
createSSRApp
|
||||
} from "vue";
|
||||
import App from "./App.vue";
|
||||
import 'virtual:uno.css'
|
||||
import { setupStore } from '@/store';
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App);
|
||||
setupStore(app);
|
||||
return {
|
||||
app,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
{
|
||||
"name" : "",
|
||||
"appid" : "",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion" : "3"
|
||||
}
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/home/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/revert/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "上报"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/statement/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报表"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "pages/data",
|
||||
"pages": [
|
||||
{
|
||||
"path": "brokerage/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "提成数据"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "performance/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "业绩数据"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "upload/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "上传数据"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/user",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "员工管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "update",
|
||||
"style": {
|
||||
"navigationBarTitleText": "修改信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "员工详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/setting",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设置"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "password",
|
||||
"style": {
|
||||
"navigationBarTitleText": "修改密码"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "complain",
|
||||
"style": {
|
||||
"navigationBarTitleText": "举报投诉"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "suggestion",
|
||||
"style": {
|
||||
"navigationBarTitleText": "意见箱"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/task",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "任务列表"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "submit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "任务提交"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "task_hygienes_submit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "清洁任务提交"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "task_ledgers_submit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "数据上报"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "任务详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/expense-account",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报销管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "submit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报销提交"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/work",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "升职申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "升职申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "升职申请"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/make-card",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡审核"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/ask-leave",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/train-books",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "培训课件"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "培训课件"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/examination",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "培训考试"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "培训考试"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColorTop": "#FFFFFF",
|
||||
"app-plus": {
|
||||
"bounce": "none",
|
||||
"scrollIndicator": "none"
|
||||
}
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#333",
|
||||
"selectedColor": "#ff3c2a",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/home/index",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/revert/index",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "上报"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/statement/index",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "报表"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine/index",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
},
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
"^uv-(.*)": "@climblee/uv-ui/components/uv-$1/uv-$1.vue"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/home/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/revert/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "上报"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/statement/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报表"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "pages/data",
|
||||
"pages": [
|
||||
{
|
||||
"path": "brokerage/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "提成数据"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "performance/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "业绩数据"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "upload/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "上传数据"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/user",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "员工管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "update",
|
||||
"style": {
|
||||
"navigationBarTitleText": "修改信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "员工详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/setting",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设置"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "password",
|
||||
"style": {
|
||||
"navigationBarTitleText": "修改密码"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "complain",
|
||||
"style": {
|
||||
"navigationBarTitleText": "举报投诉"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "suggestion",
|
||||
"style": {
|
||||
"navigationBarTitleText": "意见箱"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/task",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "任务列表"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "submit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "任务提交"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "task_hygienes_submit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "清洁任务提交"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "task_ledgers_submit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "数据上报"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "任务详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/expense-account",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报销管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "submit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报销提交"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/work",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "升职申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "升职申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "升职申请"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/make-card",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡审核"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/ask-leave",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/business",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "出差报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "出差报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "出差详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/overtime",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/contract",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},{
|
||||
"root": "pages/train-books",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "培训课件"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "培训课件"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/examination",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "培训考试"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "培训考试"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColorTop": "#FFFFFF",
|
||||
"app-plus": {
|
||||
"bounce": "none",
|
||||
"scrollIndicator": "none"
|
||||
}
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#333",
|
||||
"selectedColor": "#ff3c2a",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/home/index",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/revert/index",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "上报"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/statement/index",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "报表"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine/index",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
},
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
"^uv-(.*)": "@climblee/uv-ui/components/uv-$1/uv-$1.vue"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx" @click="goPath">
|
||||
<view class="text-30rpx"> 请假申请</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx">请假类型:</view>
|
||||
<view class="">{{ item.type.name }}</view>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx">请假事由:</view>
|
||||
<view class="">{{ item.reason }}</view>
|
||||
</view>
|
||||
<view class="flex items-center text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx"> 申请时间:</view>
|
||||
<view class="text-24rpx">{{ timeFormat(item.created_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.workflow_check.check_status, 'workflow_check', 'color')
|
||||
}"
|
||||
class="text-24rpx"
|
||||
>{{ statusFun(item.workflow_check.check_status, "workflow_check", "name") }}</view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import statusFun from "@/utils/status"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const props = defineProps({
|
||||
item: Object
|
||||
})
|
||||
const goPath = () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/ask-leave/detail?id=${props.item.id}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="请假申请">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="250rpx">
|
||||
<uv-form-item required label="请假类别" prop="type_id">
|
||||
<uv-input
|
||||
placeholder="请选择"
|
||||
@click="openPicker"
|
||||
readonly
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.type_id"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="请假开始时间" prop="start_at">
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
readonly
|
||||
@click="openStartDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.start_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item required label="请假结束时间" prop="end_at">
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
readonly
|
||||
@click="openEndDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.end_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="请假理由" prop="reason" labelPosition="top">
|
||||
<uv-textarea v-model="form.reason" count placeholder="请输入" :border="`none`" :maxlength="200"></uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<uv-picker ref="pickerRef" :columns="columns" @confirm="confirmPicker"></uv-picker>
|
||||
<uv-datetime-picker
|
||||
placeholder="请选择日期"
|
||||
v-model="startValue"
|
||||
ref="dateStartPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmStartDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-datetime-picker
|
||||
v-model="endValue"
|
||||
placeholder="请选择日期"
|
||||
ref="dateEndPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmEndDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { http } from "@/utils/request"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const columns = ref([])
|
||||
const pickerData = ref([])
|
||||
const formRef = ref(null)
|
||||
const dateStartPicker = ref(null)
|
||||
const dateEndPicker = ref(null)
|
||||
const pickerRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const startValue = ref(Number(new Date()))
|
||||
const endValue = ref(Number(new Date()))
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
start_at: "",
|
||||
end_at: "",
|
||||
reason: "",
|
||||
type_id: ""
|
||||
})
|
||||
const openPicker = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const openStartDatePicker = () => {
|
||||
dateStartPicker.value.open()
|
||||
}
|
||||
const openEndDatePicker = () => {
|
||||
dateEndPicker.value.open()
|
||||
}
|
||||
const confirmStartDatePicker = e => {
|
||||
form.start_at = timeFormat(e.value, "yyyy-mm-dd hh:MM:ss")
|
||||
}
|
||||
const confirmEndDatePicker = e => {
|
||||
form.end_at = timeFormat(e.value, "yyyy-mm-dd hh:MM:ss")
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
form.type_id = e.value[0]
|
||||
}
|
||||
const rules = reactive({
|
||||
start_at: [{ required: true, message: "请选择时间" }],
|
||||
end_at: [{ required: true, message: "请选择时间" }],
|
||||
reason: [{ required: true, message: "请输入请假理由" }],
|
||||
type_id: [{ required: true, message: "请选择请假类别" }]
|
||||
})
|
||||
onLoad(options => {
|
||||
http
|
||||
.request({
|
||||
url: `/keywords?parent_key=holiday_type`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
let names = res.map(item => item.name)
|
||||
columns.value = [names]
|
||||
pickerData.value = res
|
||||
})
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http
|
||||
.request({
|
||||
url: `/hr/holidays/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
startValue.value = res.start_at * 1000
|
||||
endValue.value = res.end_at * 1000
|
||||
form.start_at = timeFormat(res.start_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.end_at = timeFormat(res.end_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.reason = res.reason
|
||||
form.type_id = res.type.name
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/hr/holidays/${id.value}` : "/hr/holidays"
|
||||
let method = id.value ? "PUT" : "POST"
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
},
|
||||
data: {
|
||||
start_at: form.start_at,
|
||||
type_id: pickerData.value.find(item => item.name === form.type_id).id,
|
||||
reason: form.reason,
|
||||
end_at: form.end_at
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "none"
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="请假详情">
|
||||
<template v-if="!isEdit" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx">
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请人</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.name }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>所属门店</view>
|
||||
<view class="text-hex-999999">{{ detail.store.title }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>电话号码</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.phone }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.created_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>请假类型</view>
|
||||
<view class="text-hex-999999">{{ detail.type.name }}</view>
|
||||
</view>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>请假开始时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.start_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>请假结束时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.end_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>请假原因</view>
|
||||
<view class="text-hex-999999 mt-20rpx">{{ detail.reason }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-100rpx">
|
||||
<view class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx">
|
||||
<view class="flex-1">
|
||||
<uv-button color="#999999" shape="circle" plain block> 拒绝 </uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block> 通过 </uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-picker ref="pickerRef" :columns="columns" @confirm="confirmPicker"></uv-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { http } from "@/utils/request"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref } from "vue"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const modalRef = ref(null)
|
||||
const columns = [["修改", "删除"]]
|
||||
const detail = ref()
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
console.log(e)
|
||||
if (e.value[0] === "删除") {
|
||||
modalRef.value.open()
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/ask-leave/create?id=${id.value}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.request({
|
||||
url: `/hr/holidays/${id.value}`,
|
||||
method: "DELETE",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "删除成功",
|
||||
icon: "none"
|
||||
})
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
http
|
||||
.request({
|
||||
url: `/hr/holidays/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
detail.value = res
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="请假申请">
|
||||
<template #right>
|
||||
<view
|
||||
@click="goPath('/pages/ask-leave/create')"
|
||||
class="text-24rpx text-white"
|
||||
>申请</view
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import Item from './components/item.vue'
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的请假',
|
||||
apiUrl: '/hr/holidays',
|
||||
},
|
||||
{
|
||||
name: '请假审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'holiday_applies',
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx" @click="goPath">
|
||||
<view class="text-30rpx">出差报备</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="text-24rpx w-120rpx text-right mr-20rpx">目的地:</view>
|
||||
<view class="">{{ item.address }}</view>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx">出差事由:</view>
|
||||
<view class="">{{ item.reason }}</view>
|
||||
</view>
|
||||
<view class="flex items-center text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx"> 申请时间:</view>
|
||||
<view class="text-24rpx">{{ timeFormat(item.created_at, "yyyy-mm-dd hh:MM:ss") }}</view>
|
||||
</view>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.workflow_check.check_status, 'workflow_check', 'color')
|
||||
}"
|
||||
class="text-24rpx"
|
||||
>{{ statusFun(item.workflow_check.check_status, "workflow_check", "name") }}</view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import statusFun from "@/utils/status"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const props = defineProps({
|
||||
item: Object
|
||||
})
|
||||
const goPath = () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/business/detail?id=${props.item.id}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="出差申请">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="250rpx">
|
||||
<uv-form-item required label="目的地" prop="address">
|
||||
<uv-input placeholder="请选择" @click="openPicker" inputAlign="right" :border="`none`" v-model="form.address">
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="出差开始时间" prop="start_at">
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
readonly
|
||||
@click="openStartDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.start_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item required label="出差结束时间" prop="end_at">
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
readonly
|
||||
@click="openEndDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.end_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="出差事由" prop="reason" labelPosition="top">
|
||||
<uv-textarea v-model="form.reason" count placeholder="请输入" :border="`none`" :maxlength="200"></uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<uv-datetime-picker
|
||||
placeholder="请选择日期"
|
||||
v-model="startValue"
|
||||
ref="dateStartPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmStartDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-datetime-picker
|
||||
v-model="endValue"
|
||||
placeholder="请选择日期"
|
||||
ref="dateEndPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmEndDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { http } from "@/utils/request"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const columns = ref([])
|
||||
const pickerData = ref([])
|
||||
const formRef = ref(null)
|
||||
const dateStartPicker = ref(null)
|
||||
const dateEndPicker = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const startValue = ref(Number(new Date()))
|
||||
const endValue = ref(Number(new Date()))
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
start_at: "",
|
||||
end_at: "",
|
||||
reason: "",
|
||||
address: ""
|
||||
})
|
||||
const openStartDatePicker = () => {
|
||||
dateStartPicker.value.open()
|
||||
}
|
||||
const openEndDatePicker = () => {
|
||||
dateEndPicker.value.open()
|
||||
}
|
||||
const confirmStartDatePicker = e => {
|
||||
form.start_at = timeFormat(e.value, "yyyy-mm-dd hh:MM:ss")
|
||||
}
|
||||
const confirmEndDatePicker = e => {
|
||||
form.end_at = timeFormat(e.value, "yyyy-mm-dd hh:MM:ss")
|
||||
}
|
||||
const rules = reactive({
|
||||
start_at: [{ required: true, message: "请选择时间" }],
|
||||
end_at: [{ required: true, message: "请选择时间" }],
|
||||
reason: [{ required: true, message: "请输入出差理由" }],
|
||||
address: [{ required: true, message: "请输入目的地" }]
|
||||
})
|
||||
onLoad(options => {
|
||||
http
|
||||
.request({
|
||||
url: `/keywords?parent_key=holiday_type`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
let names = res.map(item => item.name)
|
||||
columns.value = [names]
|
||||
pickerData.value = res
|
||||
})
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http
|
||||
.request({
|
||||
url: `/hr/offical-bussiness/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
startValue.value = res.start_at * 1000
|
||||
endValue.value = res.end_at * 1000
|
||||
form.start_at = timeFormat(res.start_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.end_at = timeFormat(res.end_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.reason = res.reason
|
||||
form.address = res.address
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/hr/offical-bussiness/${id.value}` : "/hr/offical-bussiness"
|
||||
let method = id.value ? "PUT" : "POST"
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
},
|
||||
data: {
|
||||
start_at: form.start_at,
|
||||
address: form.address,
|
||||
reason: form.reason,
|
||||
end_at: form.end_at
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "none"
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="出差详情">
|
||||
<template v-if="!isEdit" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx">
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请人</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.name }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>所属门店</view>
|
||||
<view class="text-hex-999999">{{ detail.store.title }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>电话号码</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.phone }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.created_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>目的地</view>
|
||||
<view class="text-hex-999999">{{ detail.address }}</view>
|
||||
</view>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>出差开始时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.start_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>出差结束时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.end_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>出差原因</view>
|
||||
<view class="text-hex-999999 mt-20rpx">{{ detail.reason }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-100rpx">
|
||||
<view class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx">
|
||||
<view class="flex-1">
|
||||
<uv-button color="#999999" shape="circle" plain block> 拒绝 </uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block> 通过 </uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-picker ref="pickerRef" :columns="columns" @confirm="confirmPicker"></uv-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { http } from "@/utils/request"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref } from "vue"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const modalRef = ref(null)
|
||||
const columns = [["修改", "删除"]]
|
||||
const detail = ref()
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
console.log(e)
|
||||
if (e.value[0] === "删除") {
|
||||
modalRef.value.open()
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/business/create?id=${id.value}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.request({
|
||||
url: `/hr/offical-bussiness/${id.value}`,
|
||||
method: "DELETE",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "删除成功",
|
||||
icon: "none"
|
||||
})
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
http
|
||||
.request({
|
||||
url: `/hr/offical-bussiness/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
detail.value = res
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="出差申请">
|
||||
<template #right>
|
||||
<view
|
||||
@click="goPath('/pages/business/create')"
|
||||
class="text-24rpx text-white"
|
||||
>申请</view
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import Item from './components/item.vue'
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的请假',
|
||||
apiUrl: '/hr/offical-bussiness',
|
||||
},
|
||||
{
|
||||
name: '请假审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'holiday_applies',
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<view>1</view>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<view
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
@click.stop="onClick"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="text-30rpx">{{ item.name }}</view>
|
||||
</view>
|
||||
<uv-scroll-list v-if="item.images" :indicator="false">
|
||||
<view class="space-x-15rpx flex">
|
||||
<view v-for="(item, index) in item?.images ?? []" :key="index">
|
||||
<image
|
||||
:src="item + ''"
|
||||
mode="heightFix"
|
||||
style="height: 160rpx"
|
||||
></image>
|
||||
</view>
|
||||
</view>
|
||||
</uv-scroll-list>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.workflow_check.check_status, 'workflow_check', 'color'),
|
||||
}"
|
||||
class="text-24rpx"
|
||||
>{{
|
||||
statusFun(item.workflow_check.check_status, 'workflow_check', 'name')
|
||||
}}</view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import statusFun from '@/utils/status'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const props = defineProps({
|
||||
item: Object,
|
||||
})
|
||||
|
||||
const onClick = () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/contract/detail?id=${props.item.id}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
<template>
|
||||
<view class="">
|
||||
<CuNavbar title="合同上传">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="150rpx">
|
||||
<uv-form-item required label="合同名称" prop="name">
|
||||
<uv-input placeholder="请输入合同名称" inputAlign="right" :border="`none`" v-model="form.name"> </uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="合同照片" labelPosition="top" prop="images" required>
|
||||
<view class="w-full mt-15rpx">
|
||||
<uv-upload
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.images"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="images"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { http } from "@/utils/request"
|
||||
const formRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
name: "",
|
||||
images: []
|
||||
})
|
||||
const rules = reactive({
|
||||
name: [{ required: true, message: "请输入清洁范围" }],
|
||||
images: {
|
||||
type: "array",
|
||||
required: true,
|
||||
message: "请上传报销凭证"
|
||||
}
|
||||
})
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http
|
||||
.request({
|
||||
url: `/agreements/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
form.name = res.name
|
||||
form.images = res.images
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/agreements/${id.value}` : "/agreements"
|
||||
let method = id.value ? "PUT" : "POST"
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
},
|
||||
data: {
|
||||
name: form.name,
|
||||
images: form.images.map(item => item.url)
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "none"
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit("task:submit", resData)
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const afterRead = async event => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = form[event.name].length
|
||||
|
||||
lists.map(item => {
|
||||
form[event.name].push({
|
||||
...item,
|
||||
status: "uploading",
|
||||
message: "上传中"
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: "success",
|
||||
message: "",
|
||||
url: result
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFilePromise = url => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http
|
||||
.upload("/fileupload", {
|
||||
filePath: url,
|
||||
name: "file"
|
||||
})
|
||||
.then(res => {
|
||||
resolve(res.url)
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const deletePic = event => {
|
||||
form[event.name].splice(event.index, 1)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="合同详情">
|
||||
<template #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view
|
||||
class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx"
|
||||
>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>上传人</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.name }}</view>
|
||||
</view>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<!-- <view class="py-20rpx flex items-center justify-between">
|
||||
<view>所属门店</view>
|
||||
<view class="text-hex-999999">{{ detail.store.title }}</view>
|
||||
</view> -->
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>电话号码</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.phone }}</view>
|
||||
</view>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>上传时间</view>
|
||||
<view class="text-hex-999999">{{
|
||||
timeFormat(detail.created_at, 'yyyy-mm-dd hh:MM')
|
||||
}}</view>
|
||||
</view>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>合同名称</view>
|
||||
<view class="text-hex-999999">{{ detail.name }}</view>
|
||||
</view>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>合同内容</view>
|
||||
</view>
|
||||
<uv-scroll-list :indicator="false">
|
||||
<view class="space-x-15rpx flex">
|
||||
<view v-for="(item, index) in detail.images" :key="index">
|
||||
<image
|
||||
:src="item"
|
||||
mode="heightFix"
|
||||
style="height: 160rpx"
|
||||
></image>
|
||||
</view>
|
||||
</view>
|
||||
</uv-scroll-list>
|
||||
</view>
|
||||
<view class="h-100rpx">
|
||||
<view
|
||||
class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx"
|
||||
>
|
||||
<view class="flex-1">
|
||||
<uv-button color="#999999" shape="circle" plain block>
|
||||
拒绝
|
||||
</uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block> 通过 </uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-picker
|
||||
ref="pickerRef"
|
||||
:columns="columns"
|
||||
@confirm="confirmPicker"
|
||||
></uv-picker>
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定删除吗?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const modalRef = ref(null)
|
||||
const columns = [['修改', '删除']]
|
||||
const detail = ref()
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = (e) => {
|
||||
console.log(e)
|
||||
if (e.value[0] === '删除') {
|
||||
modalRef.value.open()
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/contract/create?id=${id.value}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.request({
|
||||
url: `/agreements/${id.value}`,
|
||||
method: 'DELETE',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
})
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'none',
|
||||
})
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
http
|
||||
.request({
|
||||
url: `/agreements/${options.id}`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
detail.value = res
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="我的合同">
|
||||
<template #right>
|
||||
<view
|
||||
@click="goPath('/pages/contract/create')"
|
||||
class="text-24rpx text-white"
|
||||
>上传</view
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
height="44"
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
:current="tabIndex"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import Item from './components/item.vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的合同',
|
||||
apiUrl: '/agreements',
|
||||
},
|
||||
{
|
||||
name: '合同审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'agreements',
|
||||
},
|
||||
},
|
||||
])
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<template>
|
||||
<view class="card">
|
||||
<view class="flex justify-between">
|
||||
<view class="font-600">{{ data.month }}</view>
|
||||
<view class="space-x-20rpx">
|
||||
<text>提成</text>
|
||||
<text class="text-primary">{{ data.commission }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex mt-20rpx">
|
||||
<view class="w-160rpx">支出</view>
|
||||
<view class="flex-1 grid grid-cols-3 text-gray-500">
|
||||
<view class="text-right">
|
||||
<text>日常:</text>
|
||||
<text>{{ data.daily_expenses }}</text>
|
||||
</view>
|
||||
<view class="text-right">
|
||||
<text>员工:</text>
|
||||
<text>{{ data.employee_expenses }}</text>
|
||||
</view>
|
||||
<view class="text-right">
|
||||
<text>其他:</text>
|
||||
<text>{{ data.other_expenses }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="提成数据" isBack></CuNavbar>
|
||||
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback">
|
||||
<view class="space-y-20rpx px-base mt-20rpx">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :data="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import Item from './components/item.vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
|
||||
const list = ref([])
|
||||
|
||||
|
||||
|
||||
const upCallback = async (mescroll) => {
|
||||
const { size, num } = mescroll
|
||||
try {
|
||||
const resData = await http.get('/account/store-master-commissions', {
|
||||
params: {
|
||||
per_page: size,
|
||||
page: num,
|
||||
},
|
||||
})
|
||||
const curPageData = resData.data || []
|
||||
if (num === 1) list.value = []
|
||||
list.value = list.value.concat(curPageData)
|
||||
mescroll.endSuccess(curPageData.length)
|
||||
} catch (error) {
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="业绩数据" isBack></CuNavbar>
|
||||
<view class="bg-primary bg-opacity-80 p-base">
|
||||
<DateTime v-model="currentDate" @confirm="dateConfirm" />
|
||||
<view class="flex items-center py-base text-white">
|
||||
<view class="flex-1 text-center">
|
||||
<view class="text-32rpx">当前业绩</view>
|
||||
<view class="mt-10rpx">{{ countData.actual_performance }}</view>
|
||||
</view>
|
||||
<view>/</view>
|
||||
<view class="flex-1 text-center">
|
||||
<view class="text-32rpx">目标业绩</view>
|
||||
<view class="mt-10rpx">{{ countData.expected_performance }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-sticky bgColor="#fff" zIndex="20">
|
||||
<view class="">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:lineColor="'#ee2c37'"
|
||||
:scrollable="false"
|
||||
:list="tabList"
|
||||
:current="currentTab"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<view class="">
|
||||
<view v-for="(ob, i) in showList" :key="i">
|
||||
<uv-sticky bgColor="#f5f5f5" zIndex="10" offsetTop="44">
|
||||
<view class="h-80rpx flex items-center px-base">
|
||||
<TitleComp :title="`${timeFormat(i, 'yyyy')}`"></TitleComp>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<view class="card">
|
||||
<view v-for="(item, i) in ob" :key="i">
|
||||
<view class="flex items-center h-84rpx">
|
||||
<view class="w-110rpx text-primary"
|
||||
>{{ timeFormat(i, 'mm') }}月</view
|
||||
>
|
||||
<view class="flex-1"
|
||||
>{{ item.actual_performance }}/{{
|
||||
item.expected_performance
|
||||
}}</view
|
||||
>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.status, 'shore_task_status', 'color'),
|
||||
}"
|
||||
>{{ statusFun(item.status, 'shore_task_status', 'name') }}</view
|
||||
>
|
||||
</view>
|
||||
<uv-line v-if="i !== ob.length - 1" color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import TitleComp from '@/components/title-comp/index'
|
||||
import DateTime from '@/components/date-time/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import statusFun from '@/utils/status'
|
||||
const list = ref([])
|
||||
const tabList = [
|
||||
{ name: '业绩目标', value: 'future' },
|
||||
{ name: '完成业绩', value: 'history' },
|
||||
]
|
||||
const currentTab = ref(0)
|
||||
const historyDate = uni.getStorageSync('historyDate')
|
||||
const currentDate = ref(historyDate || Number(new Date()))
|
||||
const countData = reactive({
|
||||
actual_performance: 0,
|
||||
expected_performance: 0,
|
||||
})
|
||||
const currentTabObj = computed(() => tabList[currentTab.value])
|
||||
const showList = computed(() => encapsulateDataByMonth(list.value))
|
||||
|
||||
onLoad(() => {
|
||||
getCount()
|
||||
getList()
|
||||
})
|
||||
|
||||
const dateConfirm = (e) => {
|
||||
uni.setStorageSync('historyDate', e.value)
|
||||
currentDate.value = e.value
|
||||
getCount()
|
||||
}
|
||||
|
||||
const getCount = async () => {
|
||||
const resData = await http.get('/account/store-performance', {
|
||||
params: {
|
||||
month: timeFormat(currentDate.value, 'yyyy-mm'),
|
||||
},
|
||||
})
|
||||
Object.assign(countData, resData)
|
||||
}
|
||||
|
||||
const tabChange = (e) => {
|
||||
currentTab.value = e.index
|
||||
getList()
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
const resData = await http.get('/account/store-performance-tasks', {
|
||||
params: {
|
||||
filter: currentTabObj.value.value,
|
||||
},
|
||||
})
|
||||
list.value = resData
|
||||
}
|
||||
|
||||
function encapsulateDataByMonth(data) {
|
||||
return data.reduce((result, item) => {
|
||||
const { month, ...rest } = item
|
||||
result[month] = result[month] || []
|
||||
result[month].push(rest)
|
||||
return result
|
||||
}, {})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="数据上报"></CuNavbar>
|
||||
<view class="mt-30rpx">
|
||||
<uv-form
|
||||
labelWidth="140rpx"
|
||||
labelPosition="left"
|
||||
:borderBottom="false"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
ref="formRef"
|
||||
>
|
||||
<view class="space-y-15rpx">
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<uv-form-item label="日期">
|
||||
<view class="w-full">
|
||||
{{ form.date }}
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
|
||||
<view> </view>
|
||||
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<uv-form-item>
|
||||
<TitleComp title="电彩" textSize="32rpx"></TitleComp>
|
||||
</uv-form-item>
|
||||
<uv-form-item label="销售" borderBottom>
|
||||
<uv-input
|
||||
border="none"
|
||||
placeholder="请输入电彩销售金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item label="兑奖">
|
||||
<uv-input
|
||||
border="none"
|
||||
placeholder="请输入电彩兑奖金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<uv-form-item>
|
||||
<TitleComp title="汇总情况" textSize="32rpx"></TitleComp>
|
||||
</uv-form-item>
|
||||
<uv-form-item label="销售合计" borderBottom>
|
||||
<uv-input
|
||||
border="none"
|
||||
placeholder="请输入总帐销售金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item label="兑奖合计" borderBottom>
|
||||
<uv-input
|
||||
border="none"
|
||||
placeholder="请输入总帐兑奖金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item label="新增客户" borderBottom>
|
||||
<uv-input
|
||||
border="none"
|
||||
placeholder="请输入微信新增人数"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item label="交账金额" borderBottom>
|
||||
<uv-input border="none" placeholder="请输入交账金额"></uv-input>
|
||||
</uv-form-item>
|
||||
<view class="text-primary text-xs mt-10rpx pb-base"
|
||||
>*请确保填写的交账金额正确无误</view
|
||||
>
|
||||
</view>
|
||||
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base pb-base">
|
||||
<uv-form-item>
|
||||
<view class="w-full">
|
||||
<TitleComp title="时段报表照片" textSize="32rpx">
|
||||
<template #right>
|
||||
<view class="text-hex-999999"> 0/9 </view>
|
||||
</template>
|
||||
</TitleComp>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<uv-form-item>
|
||||
<uv-upload></uv-upload>
|
||||
</uv-form-item>
|
||||
<view class="text-primary text-xs">
|
||||
*竞彩时段报表照片,玩法时段报表照片,每日账本上传(需亲笔签字),销量本上传
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uv-form>
|
||||
</view>
|
||||
|
||||
<uv-datetime-picker ref="datetimePicker" v-model="form.date" mode="date">
|
||||
</uv-datetime-picker>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import TitleComp from '@/components/title-comp/index'
|
||||
import { ref, reactive } from 'vue'
|
||||
const formRef = ref(null)
|
||||
const datetimePicker = ref(null)
|
||||
const form = reactive({
|
||||
date: '2022-01-01',
|
||||
})
|
||||
const rules = reactive({})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="培训考试">
|
||||
<template v-if="!readonly" #right>
|
||||
<view class="text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
|
||||
<uv-sticky bgColor="#fff">
|
||||
<view class="flex items-center justify-between h-90rpx px-base">
|
||||
<view class="w-140rpx">
|
||||
<view class="btn" :disabled="index == 0" @click="prev">上一题</view>
|
||||
</view>
|
||||
<view>{{ index + 1 }}/{{ total }}</view>
|
||||
<view class="w-140rpx text-right">
|
||||
<view class="btn" :disabled="index == total - 1" @click="next">
|
||||
下一题</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<view class="p-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base min-h-30vh">
|
||||
<template v-for="(item, key) in list" :key="key">
|
||||
<view v-show="key == index" class="item">
|
||||
<view class="title text-30rpx"
|
||||
>({{ item.cate_name }}){{ item.title }}
|
||||
|
||||
<text v-if="readonly" class="text-primary"
|
||||
>(得分:{{ item.user_score }})</text
|
||||
>
|
||||
</view>
|
||||
<view
|
||||
class="pt-base"
|
||||
:class="[readonly ? 'pointer-events-none' : '']"
|
||||
>
|
||||
<template v-if="item.cate == 2">
|
||||
<uv-checkbox-group
|
||||
activeColor="#ee2c37"
|
||||
v-model="item.answer"
|
||||
placement="column"
|
||||
>
|
||||
<uv-checkbox
|
||||
:customStyle="{ margin: '8px' }"
|
||||
v-for="(op, i) in item.options"
|
||||
:key="i"
|
||||
:label="op.text"
|
||||
:name="op.text"
|
||||
>
|
||||
</uv-checkbox>
|
||||
</uv-checkbox-group>
|
||||
</template>
|
||||
<template v-if="item.cate == 1">
|
||||
<uv-radio-group
|
||||
activeColor="#ee2c37"
|
||||
v-model="item.answer"
|
||||
placement="column"
|
||||
>
|
||||
<uv-radio
|
||||
:customStyle="{ margin: '8px' }"
|
||||
v-for="(op, i) in item.options"
|
||||
:key="i"
|
||||
:label="op.text"
|
||||
:name="op.text"
|
||||
>
|
||||
</uv-radio>
|
||||
</uv-radio-group>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
:content="`是否确认提交?`"
|
||||
@confirm="onSubmit"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { computed, ref } from 'vue'
|
||||
const modalRef = ref(null)
|
||||
const info = ref({})
|
||||
const id = ref(0)
|
||||
// 考题记录
|
||||
// const list = ref([])
|
||||
// 总题数
|
||||
// const total = ref(0)
|
||||
// 序号
|
||||
const index = ref(0)
|
||||
// 只读模式
|
||||
// const readonly = ref(true)
|
||||
const loading = ref(false)
|
||||
const list = computed(() => {
|
||||
const content = info.value?.content ?? []
|
||||
content.forEach((item) => {
|
||||
if (item.score == 1) {
|
||||
item.answer = item.user_answer[0] ?? ''
|
||||
} else {
|
||||
item.answer = item.user_answer ?? []
|
||||
}
|
||||
})
|
||||
return info.value.content || []
|
||||
})
|
||||
const total = computed(() => list.value.length)
|
||||
const readonly = computed(() => (info.value.finished_at ? true : false))
|
||||
|
||||
const answer = computed(() => {
|
||||
const arr = list.value.reduce((a, b) => {
|
||||
const c = [].concat(b.answer ?? [])
|
||||
a.push(c)
|
||||
return a
|
||||
}, [])
|
||||
return arr || []
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
http.get(`/train/examinations/${options.id}`).then((resData) => {
|
||||
const res = resData
|
||||
info.value = res
|
||||
})
|
||||
})
|
||||
|
||||
const next = () => {
|
||||
if (index.value < total.value - 1) {
|
||||
index.value++
|
||||
}
|
||||
}
|
||||
const prev = () => {
|
||||
if (index.value > 0) {
|
||||
index.value--
|
||||
}
|
||||
}
|
||||
const submit = () => {
|
||||
modalRef.value.open()
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
await http.post(`/train/examinations/${id.value}/answer`, {
|
||||
answers: answer.value,
|
||||
})
|
||||
uni.$emit('examination:onRefresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.btn {
|
||||
@apply text-28rpx;
|
||||
}
|
||||
.btn[disabled='true'] {
|
||||
color: #999;
|
||||
@apply pointer-events-none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="培训考试"></CuNavbar>
|
||||
<MescrollItem :top="88" :i="0" apiUrl="/train/examinations">
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<template v-for="item in list" :key="item.id">
|
||||
<view
|
||||
class="card-shadow space-y-10rpx bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
@click="detail(item)"
|
||||
>
|
||||
<view class="text-30rpx">{{ item.examination.name }}</view>
|
||||
<view
|
||||
class="flex items-center justify-between text-24rpx text-hex-999999"
|
||||
>
|
||||
<view class=""
|
||||
>发布日期:
|
||||
{{ timeFormat(item.examination.published_at) }}</view
|
||||
>
|
||||
<view class="">{{
|
||||
item.mark != null ? item.mark : '未完成'
|
||||
}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import MescrollItem from '@/components/mescroll-api/one'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollComp from '@/uni_modules/mescroll-uni/hooks/useMescrollComp.js'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const { mescrollItem } = useMescrollComp(onPageScroll, onReachBottom)
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('examination:onRefresh', () => {
|
||||
mescrollItem.value?.refresh()
|
||||
})
|
||||
})
|
||||
|
||||
const detail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/examination/detail?id=${item.id}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="报销管理">
|
||||
<template #right>
|
||||
<view
|
||||
@click="goPath('/pages/expense-account/submit')"
|
||||
class="text-24rpx text-white"
|
||||
>申请</view
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback">
|
||||
<view class="px-base space-y-20rpx mt-30rpx">
|
||||
<view
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="text-30rpx"> {{ item.type.name }} </view>
|
||||
<view
|
||||
:style="[
|
||||
{
|
||||
color: statusFun(
|
||||
item.workflow_check.check_status,
|
||||
'statusExpense',
|
||||
'color'
|
||||
),
|
||||
},
|
||||
]"
|
||||
class="text-24rpx"
|
||||
>{{ item.workflow_check.check_status_text }}</view
|
||||
>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="w-140rpx">报销金额</view>
|
||||
<view class="text-primary">{{ item.expense }}</view>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="w-140rpx">报销时间</view>
|
||||
<view class="text-hex-333">{{ timeFormat(item.created_at) }}</view>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999">
|
||||
<view class="">
|
||||
<text class="w-140rpx inline-block">报销原因:</text>
|
||||
<text class="text-hex-333 leading-27rpx">{{ item.reason }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import statusFun from '@/utils/status'
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const list = ref([])
|
||||
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的报销',
|
||||
},
|
||||
{
|
||||
name: '报销审核',
|
||||
},
|
||||
])
|
||||
|
||||
const upCallback = async (mescroll) => {
|
||||
const { size, num } = mescroll
|
||||
|
||||
try {
|
||||
const resData = await http.get('/reimbursements', {
|
||||
params: {
|
||||
per_page: size,
|
||||
page: num,
|
||||
},
|
||||
})
|
||||
const curPageData = resData || []
|
||||
if (num === 1) list.value = []
|
||||
list.value = list.value.concat(curPageData)
|
||||
mescroll.endSuccess(curPageData.length)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
} finally {
|
||||
// firstloading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="报销申请"> </CuNavbar>
|
||||
<view class="space-y-base mt-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<uv-form
|
||||
labelWidth="160rpx"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
ref="formRef"
|
||||
labelPosition="left"
|
||||
>
|
||||
<uv-form-item label="报销分类" required prop="reimbursement_type_id">
|
||||
<view
|
||||
@click="openType"
|
||||
keyName="name"
|
||||
class="h-full w-full flex justify-end"
|
||||
>
|
||||
{{ type.name }}
|
||||
<uv-icon name="arrow-right"></uv-icon>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="报销金额" required prop="expense">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
placeholder="请输入报销金额"
|
||||
type="digit"
|
||||
input-align="right"
|
||||
v-model="form.expense"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
label="报销原因"
|
||||
required
|
||||
prop="reason"
|
||||
:borderBottom="true"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-textarea
|
||||
:border="`none`"
|
||||
v-model="form.reason"
|
||||
placeholder="请输入报销原因"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
<uv-form-item
|
||||
label="报销凭证"
|
||||
labelPosition="top"
|
||||
prop="photos"
|
||||
required
|
||||
>
|
||||
<view class="w-full mt-15rpx">
|
||||
<uv-upload
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
|
||||
<uv-picker
|
||||
ref="typeRef"
|
||||
keyName="name"
|
||||
:columns="[typeList]"
|
||||
@confirm="typeConfirm"
|
||||
></uv-picker>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交报销申请?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import Cell from '@/components/cell/index'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
const typeRef = ref(null)
|
||||
const typeList = ref([])
|
||||
const type = ref({})
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
reimbursement_type_id: '',
|
||||
expense: '',
|
||||
reason: '',
|
||||
photos: [],
|
||||
})
|
||||
const rules = reactive({
|
||||
reimbursement_type_id: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择报销分类',
|
||||
},
|
||||
],
|
||||
expense: [{ required: true, message: '请输入报销金额' }],
|
||||
reason: [{ required: true, message: '请输入报销原因' }],
|
||||
photos: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: '请上传报销凭证',
|
||||
},
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
getTypes()
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
const resData = await http.post('/reimbursements', {
|
||||
reimbursement_type_id: form.reimbursement_type_id,
|
||||
expense: form.expense,
|
||||
reason: form.reason,
|
||||
photos: form.photos.map((item) => item.url),
|
||||
})
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('ex:submit', resData)
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const afterRead = async (event) => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = form[event.name].length
|
||||
|
||||
lists.map((item) => {
|
||||
form[event.name].push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中',
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFilePromise = (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http
|
||||
.upload('/fileupload', {
|
||||
filePath: url,
|
||||
name: 'file',
|
||||
})
|
||||
.then((res) => {
|
||||
resolve(res.url)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const deletePic = (event) => {
|
||||
form[event.name].splice(event.index, 1)
|
||||
}
|
||||
const getTypes = () => {
|
||||
http.get('/keyword?parent_key=reimbursement_type').then((res) => {
|
||||
typeList.value = res
|
||||
})
|
||||
}
|
||||
|
||||
const typeConfirm = ({ value }) => {
|
||||
type.value = value[0]
|
||||
form.reimbursement_type_id = type.value.id
|
||||
}
|
||||
|
||||
const openType = () => {
|
||||
typeRef.value.open()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<view>
|
||||
<qiun-data-charts type="area" :opts="opts" :chartData="chartData" />
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const opts = ref({
|
||||
color: [
|
||||
'#ee2c37',
|
||||
|
||||
],
|
||||
padding: [15, 15, 0, 15],
|
||||
enableScroll: false,
|
||||
legend: {
|
||||
show:false
|
||||
},
|
||||
xAxis: {
|
||||
disableGrid: true,
|
||||
},
|
||||
yAxis: {
|
||||
gridType: 'dash',
|
||||
dashLength: 2,
|
||||
},
|
||||
extra: {
|
||||
area: {
|
||||
type: 'curve',
|
||||
opacity: 0.2,
|
||||
addLine: true,
|
||||
width: 2,
|
||||
gradient: true,
|
||||
activeType: 'hollow',
|
||||
},
|
||||
},
|
||||
})
|
||||
const chartData = ref({
|
||||
categories: ['2016', '2017', '2018', '2019', '2020', '2021'],
|
||||
series: [
|
||||
{
|
||||
name: '目标值',
|
||||
data: [35, 36, 31, 33, 13, 34],
|
||||
}
|
||||
],
|
||||
})
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,193 @@
|
|||
<template>
|
||||
<view>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<view class="flex-center h-44px">
|
||||
<view class="flex-center flex-1" @click="selectMenu({ name: 'shore' })">
|
||||
<view>全部区域</view>
|
||||
<uv-icon
|
||||
class="ml-10rpx"
|
||||
size="20rpx"
|
||||
name="arrow-down-fill"
|
||||
></uv-icon>
|
||||
</view>
|
||||
<view class="flex-center flex-1" @click="selectMenu({ name: 'store' })">
|
||||
<view>全部区域</view>
|
||||
<uv-icon
|
||||
class="ml-10rpx"
|
||||
size="20rpx"
|
||||
name="arrow-down-fill"
|
||||
></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<uv-picker
|
||||
ref="shoreRef"
|
||||
keyName="name"
|
||||
@change="shoreChange"
|
||||
:columns="shoreList"
|
||||
@confirm="shoreConfirm"
|
||||
></uv-picker>
|
||||
|
||||
<uv-picker
|
||||
ref="storeRef"
|
||||
keyName="address"
|
||||
@change="shoreChange"
|
||||
:columns="storeList"
|
||||
@confirm="shoreConfirm"
|
||||
></uv-picker>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { http } from '@/utils/request'
|
||||
import data from './da.json'
|
||||
|
||||
export default {
|
||||
onPageScroll() {
|
||||
// 滚动后及时更新位置
|
||||
// this.$refs.dropDown.init()
|
||||
},
|
||||
computed: {
|
||||
dropItem(name) {
|
||||
return (name) => {
|
||||
return {
|
||||
label: name,
|
||||
value: name,
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取当前下拉筛选项
|
||||
currentDropItem() {
|
||||
return this[this.activeName]
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
shoreList: [],
|
||||
storeList: [],
|
||||
// 表示value等于这些值,就属于默认值
|
||||
defaultValue: [0, 'all'],
|
||||
// 筛选结果
|
||||
result: [],
|
||||
activeName: 'shore',
|
||||
shore: {
|
||||
label: '全部区域',
|
||||
activeIndex: [0, 0],
|
||||
color: '#333',
|
||||
activeColor: '#2878ff',
|
||||
},
|
||||
store: {
|
||||
label: '全部门店',
|
||||
activeIndex: 0,
|
||||
color: '#333',
|
||||
activeColor: '#2878ff',
|
||||
},
|
||||
cityData: data,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
async init() {
|
||||
const province = this.cityData.province
|
||||
this.shoreList = [
|
||||
province,
|
||||
this.getCityByProvince(province[this.shore.activeIndex[1]].code),
|
||||
]
|
||||
},
|
||||
change(e) {
|
||||
console.log('弹窗打开状态:', e)
|
||||
},
|
||||
/**
|
||||
* 点击每个筛选项回调
|
||||
* @param {Object} e { name, active, type } = e
|
||||
*/
|
||||
selectMenu(e) {
|
||||
const { name } = e
|
||||
this.activeName = name
|
||||
if (name === 'shore') {
|
||||
const active = this.shore.activeIndex
|
||||
const list = this.getCityByProvince(this.shoreList[0][active[0]].code)
|
||||
this.shoreList[1] = list
|
||||
this.$refs.shoreRef.setColumnValues(1, list)
|
||||
this.$refs.shoreRef.setIndexs(active, true)
|
||||
this.$refs.shoreRef.open()
|
||||
}
|
||||
if (name === 'store') {
|
||||
this.$refs.storeRef.open()
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 点击菜单回调处理
|
||||
* @param {Object} item 选中项 { label,value } = e
|
||||
*/
|
||||
clickItem(e) {},
|
||||
shoreChange(e) {
|
||||
const { columnIndex, index } = e
|
||||
if (columnIndex == 0) {
|
||||
const item = this.shoreList[columnIndex][index]
|
||||
this.shoreList[1] = this.getCityByProvince(item.code)
|
||||
this.$refs.shoreRef.setColumnValues(
|
||||
1,
|
||||
this.getCityByProvince(item.code)
|
||||
)
|
||||
}
|
||||
},
|
||||
shoreConfirm(e) {
|
||||
this.shore.activeIndex = e.indexs
|
||||
const item = {
|
||||
name: 'shore',
|
||||
}
|
||||
const cityIndex = this.shore.activeIndex[1]
|
||||
const index = cityIndex == 0 ? 0 : 1
|
||||
const index2 = e.indexs[index]
|
||||
},
|
||||
getCityByProvince(province) {
|
||||
return [
|
||||
{
|
||||
name: '全部',
|
||||
code: 'all',
|
||||
},
|
||||
].concat(this.cityData.city[province])
|
||||
},
|
||||
|
||||
getStoreByCity(city) {
|
||||
const res = http.get('/auth/stores', {
|
||||
params: {
|
||||
city: city,
|
||||
},
|
||||
})
|
||||
this.storeList = [
|
||||
{
|
||||
id: 1,
|
||||
title: '1',
|
||||
master_id: 1,
|
||||
category_id: 'store_category_1_1',
|
||||
business_id: 'store_business_1',
|
||||
level_id: 'store_level_2',
|
||||
region: {
|
||||
city: '天津市市辖区',
|
||||
code: 120100,
|
||||
street: null,
|
||||
cityCode: 120100,
|
||||
district: null,
|
||||
province: '天津市',
|
||||
districtCode: 0,
|
||||
provinceCode: 120000,
|
||||
},
|
||||
address: '回龙观(地铁站)',
|
||||
lon: '116.34266369754',
|
||||
lat: '40.076418413591',
|
||||
profit_ratio: 0,
|
||||
profit_money: '0.00',
|
||||
business_status: 1,
|
||||
created_at: '2024-04-03 17:17:02',
|
||||
updated_at: '2024-04-03 17:17:02',
|
||||
business_status_text: '开业',
|
||||
business_status_color: 'success',
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<view>
|
||||
<view>
|
||||
<StoreDropDown></StoreDropDown>
|
||||
</view>
|
||||
|
||||
<view class="bg-primary p-base text-center text-white relative">
|
||||
<view class="absolute top-20rpx right-20rpx">
|
||||
<uv-icon color="#fff" size="48rpx" name="chat"></uv-icon>
|
||||
</view>
|
||||
<view class="mt-60rpx">昨日累计金额</view>
|
||||
<view class="mt-20rpx">截止2024-03-21</view>
|
||||
<view class="flex items-center mt-40rpx">
|
||||
<view class="flex-1 text-center">
|
||||
<view>销售</view>
|
||||
<view>20000</view>
|
||||
</view>
|
||||
<view class="h-80rpx flex-none flex-center">
|
||||
<uv-line direction="vertical"></uv-line>
|
||||
</view>
|
||||
<view class="flex-1 text-center">
|
||||
<view>支出</view>
|
||||
<view>20000</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view class="h-80rpx leading-80rpx px-base">近30天趋势数据</view>
|
||||
</view>
|
||||
<view>
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
lineColor="#ee2c37"
|
||||
:list="list"
|
||||
@click="onTabClick"
|
||||
:scrollable="false"
|
||||
></uv-tabs>
|
||||
<ChartComp></ChartComp>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import ChartComp from './components/chart.vue'
|
||||
import StoreDropDown from '@/pages/home/components/store-drop-down/index.vue'
|
||||
|
||||
const list = ref([
|
||||
{
|
||||
name: '销售金额',
|
||||
},
|
||||
{
|
||||
name: '支出金额',
|
||||
},
|
||||
])
|
||||
|
||||
const onTabClick = (e) => {
|
||||
console.log(e)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<view class="content">
|
||||
<uv-icon name="photo" size="30" color="#909399"></uv-icon>
|
||||
<uv-button type="primary" text="确定">我是按钮</uv-button>
|
||||
<image class="logo" src="/static/logo.png"></image>
|
||||
<view class="text-area">
|
||||
<text class="title">{{ title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
title: 'Hello',
|
||||
}
|
||||
},
|
||||
onLoad() {},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 200rpx;
|
||||
width: 200rpx;
|
||||
margin-top: 200rpx;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.text-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
color: #8f8f94;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
|
||||
<template>
|
||||
<view class="w-full flex flex-col">
|
||||
<view class="mt-20vh">
|
||||
<view class="b-1px b-solid h-120rpx"></view>
|
||||
</view>
|
||||
<view class="text-35rpx text-hex-333333 font-600 mt-80rpx">体彩管理系统</view>
|
||||
<view class="text-27rpx text-hex-333333">欢迎登录</view>
|
||||
<view class="flex-1 flex flex-col justify-end mt-0rpx">
|
||||
<LoginForm></LoginForm>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import LoginForm from './LoginForm.vue'
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<template>
|
||||
<view class="">
|
||||
<uv-form>
|
||||
<uv-form-item>
|
||||
<view class="h-92rpx bg-white rounded-full w-full flex-center">
|
||||
<uv-input
|
||||
v-model="form.username"
|
||||
shape="circle"
|
||||
maxlength="11"
|
||||
placeholder="请输入帐号"
|
||||
type="text"
|
||||
border="none1"
|
||||
fontSize="27rpx"
|
||||
>
|
||||
</uv-input>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
|
||||
<uv-form-item>
|
||||
<view class="h-92rpx bg-white rounded-full w-full flex-center">
|
||||
<uv-input
|
||||
v-model="form.password"
|
||||
shape="circle"
|
||||
placeholder="请输入密码"
|
||||
type="password"
|
||||
border="none1"
|
||||
fontSize="27rpx"
|
||||
>
|
||||
</uv-input>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
<view class="mt-115rpx">
|
||||
<uv-button block type="primary" shape="circle" @click="handleClick"
|
||||
>登录</uv-button
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const form = ref({
|
||||
username: '',
|
||||
password: '',
|
||||
})
|
||||
|
||||
const handleClick = async () => {
|
||||
try {
|
||||
// const { username, password } = form.value
|
||||
// await userStore.login({
|
||||
// username,
|
||||
// password,
|
||||
// })
|
||||
uni.switchTab({
|
||||
url: '/pages/home/index',
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<view>
|
||||
|
||||
<view class="mt-115rpx">
|
||||
<uv-button block type="primary_btn1" shape="circle" open-type="getPhoneNumber"
|
||||
@getphonenumber="getPhoneNumber">微信一键登录
|
||||
</uv-button>
|
||||
<view class="mt-31rpx">
|
||||
<cu-checkbox v-model="checkbox">
|
||||
<view class="flex items-center flex-wrap text-23rpx leading-33rpx text-hex-333333">
|
||||
<view class="text-hex-999999 float-left">
|
||||
登录即代表同意
|
||||
</view>
|
||||
<text>《用户协议》《隐私政策》</text>
|
||||
<text class="text-hex-999999">
|
||||
及
|
||||
</text>
|
||||
<text>《第三方SDK类服务商说明》</text>
|
||||
</view>
|
||||
</cu-checkbox>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import CuCheckbox from "@/components/CuCheckbox/cu-checkbox.vue";
|
||||
import {ref} from 'vue'
|
||||
import {useUserStore} from "@/store/modules/user";
|
||||
|
||||
const userStore = useUserStore()
|
||||
const checkbox = ref(false)
|
||||
|
||||
const getPhoneNumber = (e) => {
|
||||
|
||||
const {appId, version} = uni.getAccountInfoSync().miniProgram
|
||||
userStore.wchatLogin({
|
||||
appId,
|
||||
version,
|
||||
type: 'getPhoneNumber',
|
||||
code: e.code
|
||||
})
|
||||
|
||||
uni.switchTab({
|
||||
url: '/pages/tabbar/home',
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<template>
|
||||
<Cupopup mode="bottom" v-model:visible="ruleShow" title="请阅读并同意以下条款" @cancel="handleClick('cancel')"
|
||||
@confirm="handleClick('confirm')">
|
||||
<view @click="ruleClick">
|
||||
登录即代表同意《用户协议》、《隐私政策》 登录即代表同意《用户协议》、《隐私政策》及《第三方SDK类服务商说明》
|
||||
</view>
|
||||
</Cupopup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Cupopup from "@/components/CuPopup/index.vue";
|
||||
import {ref, watch, watchEffect} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
})
|
||||
|
||||
const ruleShow = ref(props.visible)
|
||||
const emit = defineEmits(['update:visible', 'onClick','ruleClick'])
|
||||
const handleClick = (e) => {
|
||||
emit('onClick', e)
|
||||
}
|
||||
|
||||
const ruleClick = () => {
|
||||
emit('ruleClick')
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
ruleShow.value = props.visible
|
||||
})
|
||||
|
||||
watch(() => ruleShow.value, (val) => {
|
||||
emit('update:visible', val)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<Cupopup mode="bottom" v-model:visible="ruleShow" title="用户服务协议及隐私政策" @cancel="handleClick('cancel')" @confirm="handleClick('confirm')">
|
||||
<view class="space-y-20rpx">
|
||||
<view class="indent-46rpx">
|
||||
小程序用户协议和隐私政策是小程序开发者为保障用户合法权益和保护用户隐私而制
|
||||
</view>
|
||||
<view>定的两个重要文件。下面分别介绍一下小程序用户协议和隐私政策的内容和要点:</view>
|
||||
<view>用户协议: 用户协议是小程序开发者与用户之间达成的协议, 规定了用户使用小程序的
|
||||
条件、权利和义务等内容。用户在使用小程序之前需要同意用户协议,否则无法使用小程序。
|
||||
</view>
|
||||
<view> 一般来说,小程序用户协议包括以下几个方面的内容:</view>
|
||||
<view>1. 用户注册和账号管理规定:包括用户注册、账号安全和管理等规定。</view>
|
||||
<view>2. 使用规范和限制: 包括用户在小程序上发布内容的规范、禁止发布的内容和行为等规定。</view>
|
||||
<view>3. 用户权利和义务:包括用户在使用小程序时享有的权利和应承担的义务等规定。</view>
|
||||
<view>4. 免责声明和责任限制:包括小程序开发者对小程序服务的免责声明和责任限制等规定。</view>
|
||||
<view>5. 争议解决方式:包括双方在发生争议时解决方式的规定。</view>
|
||||
<view>6. 隐私政策: 隐私政策是小程序开发者为保护用户隐私而制定的政策, 规定了小程序开发
|
||||
者在收集、使用、存储、保护用户个人信息时应遵守的原则和措施。用户在使用小程序 时, 需要同意隐私政策, 否则无法使用小程序。
|
||||
一般来
|
||||
</view>
|
||||
</view>
|
||||
</Cupopup>
|
||||
</template>
|
||||
<script setup>
|
||||
import Cupopup from '@/components/CuPopup/index.vue'
|
||||
import {ref, watch, watchEffect} from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
})
|
||||
const ruleShow = ref(props.visible)
|
||||
const emit = defineEmits(['update:visible', 'onClick'])
|
||||
|
||||
const handleClick = (e) => {
|
||||
emit('onClick', e)
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
ruleShow.value = props.visible
|
||||
})
|
||||
|
||||
watch(() => ruleShow.value, (val) => {
|
||||
emit('update:visible', val)
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<template>
|
||||
<view class="px-106rpx min-h-screen">
|
||||
<Layout></Layout>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Layout from './Layout.vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
</script>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx" @click="goPath">
|
||||
<view class="text-30rpx">补卡申请</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx">补卡原因:</view>
|
||||
<view class="">{{ item.reason }}</view>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx">补卡类别:</view>
|
||||
<view class="">{{ item.sign_time == 1 ? "上班打卡" : "下班打卡" }}</view>
|
||||
</view>
|
||||
<view class="flex items-center text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx"> 补卡时间:</view>
|
||||
<view class="text-24rpx">{{ valueFormat }}</view>
|
||||
</view>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.workflow_check.check_status, 'workflow_check', 'color')
|
||||
}"
|
||||
class="text-24rpx"
|
||||
>{{ statusFun(item.workflow_check.check_status, "workflow_check", "name") }}</view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import statusFun from "@/utils/status"
|
||||
import { computed } from "vue"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const props = defineProps({
|
||||
item: Object
|
||||
})
|
||||
const valueFormat = computed(() => {
|
||||
return timeFormat(props.item.date, "yyyy-mm-dd hh:MM")
|
||||
})
|
||||
const goPath = () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/make-card/detail?id=${props.item.id}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="补卡申请">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="250rpx">
|
||||
<uv-form-item required label="补卡时间" prop="date">
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
readonly
|
||||
@click="openDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.date"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="补卡类型" prop="sign_time">
|
||||
<uv-input
|
||||
placeholder="请选择"
|
||||
@click="openPicker"
|
||||
readonly
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.sign_time"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="补卡理由" prop="reason" labelPosition="top">
|
||||
<uv-textarea v-model="form.reason" count placeholder="请输入" :border="`none`" :maxlength="200"></uv-textarea>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="外勤" prop="isOutSide">
|
||||
<view class="flex flex-1 justify-end">
|
||||
<uv-switch size="20" v-model="form.isOutSide"></uv-switch>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<uv-form-item v-if="form.isOutSide" required label="外勤事由" prop="outside_remarks" labelPosition="top">
|
||||
<uv-textarea
|
||||
v-model="form.outside_remarks"
|
||||
count
|
||||
placeholder="请输入"
|
||||
:border="`none`"
|
||||
:maxlength="200"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<uv-picker ref="pickerRef" :columns="columns" @confirm="confirmPicker"></uv-picker>
|
||||
<uv-datetime-picker
|
||||
v-model="value"
|
||||
placeholder="请选择日期"
|
||||
ref="datetimePicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { http } from "@/utils/request"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const columns = [["上班补卡", "上班补卡"]]
|
||||
const formRef = ref(null)
|
||||
const datetimePicker = ref(null)
|
||||
const pickerRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const value = ref(Number(new Date()))
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
date: "",
|
||||
sign_time: "",
|
||||
reason: "",
|
||||
outside_remarks: "",
|
||||
isOutSide: false
|
||||
})
|
||||
const openPicker = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const openDatePicker = () => {
|
||||
datetimePicker.value.open()
|
||||
}
|
||||
const confirmDatePicker = e => {
|
||||
form.date = timeFormat(e.value, "yyyy-mm-dd hh:MM")
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
form.sign_time = e.value[0]
|
||||
}
|
||||
const rules = reactive({
|
||||
date: [{ required: true, message: "请选择时间" }],
|
||||
sign_time: [{ required: true, message: "请选择类型" }],
|
||||
reason: [{ required: true, message: "请输入补卡理由" }],
|
||||
outside_remarks: [{ required: true, message: "请输入补卡理由" }]
|
||||
})
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http
|
||||
.request({
|
||||
url: `/hr/sign-repairs/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
value.value = res.date * 1000
|
||||
form.date = timeFormat(res.date, "yyyy-mm-dd hh:MM")
|
||||
form.reason = res.reason
|
||||
form.isOutSide = res.sign_type == 1 ? false : true
|
||||
form.outside_remarks = res.outside_remarks
|
||||
form.sign_time = res.sign_time == 1 ? "上班补卡" : "下班补卡"
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/hr/sign-repairs/${id.value}` : "/hr/sign-repairs"
|
||||
let method = id.value ? "PUT" : "POST"
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
},
|
||||
data: {
|
||||
date: form.date,
|
||||
sign_time: form.sign_time == "上班补卡" ? 1 : 2,
|
||||
reason: form.reason,
|
||||
outside_remarks: form.outside_remarks,
|
||||
sign_type: form.isOutSide ? 2 : 1
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "none"
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="加班审核">
|
||||
<template v-if="!isEdit" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx">
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请人</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.name }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>所属门店</view>
|
||||
<view class="text-hex-999999">{{ detail.store.title }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>电话号码</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.phone }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.created_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>补卡时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.date, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>补卡原因</view>
|
||||
<view class="text-hex-999999 mt-20rpx">{{ detail.reason }}</view>
|
||||
</view>
|
||||
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>是否外勤</view>
|
||||
<view class="text-hex-999999">{{ detail.sign_type == 1 ? "否" : "是" }}</view>
|
||||
</view>
|
||||
<template v-if="detail.sign_type == 2">
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>外勤事由</view>
|
||||
<view class="text-hex-999999 mt-20rpx">{{ detail.outside_remarks }}</view>
|
||||
</view>
|
||||
</template>
|
||||
<uv-line></uv-line>
|
||||
</view>
|
||||
<view class="h-100rpx">
|
||||
<view class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx">
|
||||
<view class="flex-1">
|
||||
<uv-button color="#999999" shape="circle" plain block> 拒绝 </uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block> 通过 </uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-picker ref="pickerRef" :columns="columns" @confirm="confirmPicker"></uv-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { http } from "@/utils/request"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref } from "vue"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const modalRef = ref(null)
|
||||
const columns = [["修改", "删除"]]
|
||||
const detail = ref()
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
console.log(e)
|
||||
if (e.value[0] === "删除") {
|
||||
modalRef.value.open()
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/make-card/create?id=${id.value}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.request({
|
||||
url: `/hr/sign-repairs/${id.value}`,
|
||||
method: "DELETE",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "删除成功",
|
||||
icon: "none"
|
||||
})
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
http
|
||||
.request({
|
||||
url: `/hr/sign-repairs/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
detail.value = res
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="补卡申请">
|
||||
<template #right>
|
||||
<view
|
||||
@click="goPath('/pages/make-card/create')"
|
||||
class="text-24rpx text-white"
|
||||
>申请</view
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import Item from './components/item.vue'
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的补卡',
|
||||
apiUrl: '/hr/sign-repairs',
|
||||
},
|
||||
{
|
||||
name: '补卡审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'employee_sign_repairs',
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<template>
|
||||
<view class="flex-center flex-col" @click="onClick">
|
||||
<uv-icon :name="data.icon" size="38" color="#909399"></uv-icon>
|
||||
<view class="text-28rpx mt-10rpx">{{ data.title }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
const onClick = () => {
|
||||
if (props.data.url) {
|
||||
uni.navigateTo({
|
||||
url: props.data.url,
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar :isBack="false" title="我的">
|
||||
<template #right>
|
||||
<view class="h-full flex-center">
|
||||
<image
|
||||
@click="goPath('/pages/setting/index')"
|
||||
class="w-32rpx h-32rpx"
|
||||
src="/static/images/setting.svg"
|
||||
></image>
|
||||
</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="px-base space-y-15rpx mt-30rpx">
|
||||
<view class="card" v-for="(item, i) in opList" :key="i">
|
||||
<TitleComp :title="item.title"></TitleComp>
|
||||
<view class="grid grid-cols-3 mt-20rpx gap-20rpx">
|
||||
<OpItem v-for="(child, ii) in item.children" :key="ii" :data="child"></OpItem>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import TitleComp from "@/components/title-comp/index"
|
||||
import OpItem from "./components/op-item.vue"
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
const opList = [
|
||||
{
|
||||
title: "门店数据",
|
||||
children: [
|
||||
{
|
||||
icon: "order",
|
||||
title: "业绩数据",
|
||||
url: "/pages/data/performance/index"
|
||||
},
|
||||
{
|
||||
icon: "folder",
|
||||
title: "提成数据",
|
||||
url: "/pages/data/brokerage/index"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "办公管理",
|
||||
children: [
|
||||
{
|
||||
icon: "photo-fill",
|
||||
title: "员工管理",
|
||||
url: "/pages/user/index"
|
||||
},
|
||||
{
|
||||
icon: "lock",
|
||||
title: "我的任务",
|
||||
url: "/pages/task/index"
|
||||
},
|
||||
{
|
||||
icon: "home-fill",
|
||||
title: "报销管理",
|
||||
url: "/pages/expense-account/index"
|
||||
},
|
||||
{
|
||||
icon: "map-fill",
|
||||
title: "升职申请",
|
||||
url: "/pages/work/list"
|
||||
},
|
||||
{
|
||||
icon: "grid-fill",
|
||||
title: "补卡申请",
|
||||
url: "/pages/make-card/list"
|
||||
},
|
||||
{
|
||||
icon: "car",
|
||||
title: "请假申请",
|
||||
url: "/pages/ask-leave/list"
|
||||
},
|
||||
{
|
||||
icon: "setting-fill",
|
||||
title: "出差报备",
|
||||
url: "/pages/business/list"
|
||||
},
|
||||
{
|
||||
icon: "server-man",
|
||||
title: "加班报备",
|
||||
url: "/pages/overtime/list"
|
||||
},
|
||||
{
|
||||
icon: "camera",
|
||||
title: "合同管理",
|
||||
url: "/pages/contract/list"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "天天向上",
|
||||
children: [
|
||||
{
|
||||
icon: "account",
|
||||
title: "培训课件",
|
||||
url: "/pages/train-books/index"
|
||||
},
|
||||
{
|
||||
icon: "twitte",
|
||||
title: "培训考试",
|
||||
url: "/pages/examination/index"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const goPath = url => {
|
||||
uni.navigateTo({
|
||||
url
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx" @click="goPath">
|
||||
<view class="text-30rpx">加班报备</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx">加班日期:</view>
|
||||
<view class="">{{ timeFormat(item.date, "yyyy-mm-dd") }}</view>
|
||||
</view>
|
||||
<view class="flex items-center text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx"> 加班时间:</view>
|
||||
<view class="text-24rpx"
|
||||
>{{ timeFormat(item.start_at, "yyyy-mm-dd hh:MM").substring(10) }} -
|
||||
{{ timeFormat(item.end_at, "yyyy-mm-dd hh:MM").substring(10) }}</view
|
||||
>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="text-24rpx w-140rpx">加班事由:</view>
|
||||
<view class="">{{ item.reason }}</view>
|
||||
</view>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.workflow_check.check_status, 'workflow_check', 'color')
|
||||
}"
|
||||
class="text-24rpx"
|
||||
>{{ statusFun(item.workflow_check.check_status, "workflow_check", "name") }}</view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import statusFun from "@/utils/status"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const props = defineProps({
|
||||
item: Object
|
||||
})
|
||||
const goPath = () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/overtime/detail?id=${props.item.id}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="加班申请">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="250rpx">
|
||||
<uv-form-item required label="日期" prop="date">
|
||||
<uv-input
|
||||
placeholder="请选择"
|
||||
readonly
|
||||
@click="openDate"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.date"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="加班开始时间" prop="start_at">
|
||||
<uv-input
|
||||
placeholder="请选择时间"
|
||||
readonly
|
||||
@click="openStartDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.start_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item required label="加班结束时间" prop="end_at">
|
||||
<uv-input
|
||||
placeholder="请选择时间"
|
||||
readonly
|
||||
@click="openEndDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.end_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="出差事由" prop="reason" labelPosition="top">
|
||||
<uv-textarea v-model="form.reason" count placeholder="请输入" :border="`none`" :maxlength="200"></uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<uv-datetime-picker
|
||||
placeholder="请选择日期"
|
||||
v-model="dateValue"
|
||||
ref="datePicker"
|
||||
mode="date"
|
||||
@confirm="confirmDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-datetime-picker
|
||||
placeholder="请选择时间"
|
||||
v-model="startValue"
|
||||
ref="dateStartPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmStartDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-datetime-picker
|
||||
v-model="endValue"
|
||||
placeholder="请选择时间"
|
||||
ref="dateEndPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmEndDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { http } from "@/utils/request"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const columns = ref([])
|
||||
const pickerData = ref([])
|
||||
const formRef = ref(null)
|
||||
const dateStartPicker = ref(null)
|
||||
const datePicker = ref(null)
|
||||
const dateEndPicker = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const startValue = ref(Number(new Date()))
|
||||
const dateValue = ref(Number(new Date()))
|
||||
const endValue = ref(Number(new Date()))
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
start_at: "",
|
||||
end_at: "",
|
||||
reason: "",
|
||||
date: ""
|
||||
})
|
||||
const openDate = () => {
|
||||
datePicker.value.open()
|
||||
}
|
||||
const openStartDatePicker = () => {
|
||||
dateStartPicker.value.open()
|
||||
}
|
||||
const openEndDatePicker = () => {
|
||||
dateEndPicker.value.open()
|
||||
}
|
||||
const confirmDatePicker = e => {
|
||||
form.date = timeFormat(e.value, "yyyy-mm-dd")
|
||||
}
|
||||
const confirmStartDatePicker = e => {
|
||||
form.start_at = timeFormat(e.value, "yyyy-mm-dd hh:MM:ss")
|
||||
}
|
||||
const confirmEndDatePicker = e => {
|
||||
form.end_at = timeFormat(e.value, "yyyy-mm-dd hh:MM:ss")
|
||||
}
|
||||
const rules = reactive({
|
||||
start_at: [{ required: true, message: "请选择时间" }],
|
||||
end_at: [{ required: true, message: "请选择时间" }],
|
||||
reason: [{ required: true, message: "请输入加班理由" }],
|
||||
date: [{ required: true, message: "请选择日期" }]
|
||||
})
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http
|
||||
.request({
|
||||
url: `/hr/overtimes/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
startValue.value = res.start_at * 1000
|
||||
endValue.value = res.end_at * 1000
|
||||
dateValue.value = res.date * 1000
|
||||
form.start_at = timeFormat(res.start_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.end_at = timeFormat(res.end_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.date = timeFormat(res.date, "yyyy-mm-dd")
|
||||
form.reason = res.reason
|
||||
form.address = res.address
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/hr/overtimes/${id.value}` : "/hr/overtimes"
|
||||
let method = id.value ? "PUT" : "POST"
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
},
|
||||
data: {
|
||||
start_at: form.start_at,
|
||||
date: form.date,
|
||||
reason: form.reason,
|
||||
end_at: form.end_at
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "none"
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="加班审核">
|
||||
<template v-if="!isEdit" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx">
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请人</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.name }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>所属门店</view>
|
||||
<view class="text-hex-999999">{{ detail.store.title }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>电话号码</view>
|
||||
<view class="text-hex-999999">{{ detail.employee.phone }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.created_at, "yyyy-mm-dd hh:MM") }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>加班日期</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.date, "yyyy-mm-dd") }}</view>
|
||||
</view>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>开始时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.start_at, "yyyy-mm-dd hh:MM").substring(10) }}</view>
|
||||
</view>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>结束时间</view>
|
||||
<view class="text-hex-999999">{{ timeFormat(detail.end_at, "yyyy-mm-dd hh:MM").substring(10) }}</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>加班原因</view>
|
||||
<view class="text-hex-999999 mt-20rpx">{{ detail.reason }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-100rpx">
|
||||
<view class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx">
|
||||
<view class="flex-1">
|
||||
<uv-button color="#999999" shape="circle" plain block> 拒绝 </uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block> 通过 </uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-picker ref="pickerRef" :columns="columns" @confirm="confirmPicker"></uv-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { http } from "@/utils/request"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref } from "vue"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const modalRef = ref(null)
|
||||
const columns = [["修改", "删除"]]
|
||||
const detail = ref()
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
console.log(e)
|
||||
if (e.value[0] === "删除") {
|
||||
modalRef.value.open()
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/overtime/create?id=${id.value}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.request({
|
||||
url: `/hr/overtimes/${id.value}`,
|
||||
method: "DELETE",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "删除成功",
|
||||
icon: "none"
|
||||
})
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
http
|
||||
.request({
|
||||
url: `/hr/overtimes/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
detail.value = res
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="加班申请">
|
||||
<template #right>
|
||||
<view
|
||||
@click="goPath('/pages/overtime/create')"
|
||||
class="text-24rpx text-white"
|
||||
>申请</view
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import Item from './components/item.vue'
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的加班',
|
||||
apiUrl: '/hr/overtimes',
|
||||
},
|
||||
{
|
||||
name: '加班审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'overtime_applies',
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar :isBack="isBack" title="上报"></CuNavbar>
|
||||
<view
|
||||
:class="[
|
||||
checkPermission(['store']) && form.allow_rereport
|
||||
? ''
|
||||
: 'pointer-events-none',
|
||||
]"
|
||||
>
|
||||
<uv-form
|
||||
class="mt-30rpx"
|
||||
labelPosition="left"
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
labelWidth="130rpx"
|
||||
>
|
||||
<view class="px-base space-y-20rpx">
|
||||
<view class="card">
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item
|
||||
label="日期"
|
||||
prop="form.date"
|
||||
@click="showDateSelect"
|
||||
>
|
||||
<uv-input
|
||||
disabled
|
||||
v-model="form.date"
|
||||
disabledColor="#ffffff"
|
||||
placeholder="请选择日期"
|
||||
:border="`none`"
|
||||
>
|
||||
</uv-input>
|
||||
<template v-slot:right>
|
||||
<uv-icon name="arrow-right"></uv-icon>
|
||||
</template>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card" v-for="(item, i) in form.items" :key="i">
|
||||
<TitleComp :title="item.name"></TitleComp>
|
||||
<view class="mt-20rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="销售" :prop="`items.${i}.sales`">
|
||||
<uv-input
|
||||
@input="salesChange"
|
||||
v-model="item.sales"
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
:placeholder="`请输入${item.name}销售金额`"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="兑奖" :prop="`items.${i}.expenditure`">
|
||||
<uv-input
|
||||
@input="expenditureChange"
|
||||
v-model="item.expenditure"
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
:placeholder="`请输入${item.name}兑奖金额`"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<TitleComp title="汇总情况"></TitleComp>
|
||||
<view class="mt-20rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="销售合计" prop="sales">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
v-model="form.sales"
|
||||
placeholder="请输入总账销售金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="兑奖合计" prop="expenditure">
|
||||
<uv-input
|
||||
type="digit"
|
||||
:border="`none`"
|
||||
v-model="form.expenditure"
|
||||
placeholder="请输入电总账兑奖金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="新增客户" prop="new_customers">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
v-model="form.new_customers"
|
||||
type="number"
|
||||
placeholder="请输入微信新增人数"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="交账金额" prop="handover_amount">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
v-model="form.handover_amount"
|
||||
placeholder="请输入交账金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<view class="text-primary text-24rpx py-10rpx"
|
||||
>* 请确保填写的交账金额正确无误!</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<TitleComp title="时段报表照片">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-gray-400"
|
||||
>{{ form.photos.length }}/9</view
|
||||
>
|
||||
</template>
|
||||
</TitleComp>
|
||||
<uv-form-item label="" prop="photos">
|
||||
<view>
|
||||
<uv-upload
|
||||
width="200rpx"
|
||||
height="200rpx"
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<view class="text-primary text-24rpx py-10rpx">
|
||||
*竞彩时段报表照片,玩法时段报表照片,每日账本上传(需亲笔签字),销量本上传
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uv-form>
|
||||
</view>
|
||||
<view class="h-130rpx">
|
||||
<view
|
||||
class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex-center box-border px-base"
|
||||
:style="style"
|
||||
>
|
||||
<view class="w-full">
|
||||
<uv-button
|
||||
:disabled="!form.allow_rereport"
|
||||
type="primary"
|
||||
shape="circle"
|
||||
block
|
||||
@click="submit"
|
||||
>
|
||||
上报
|
||||
</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-calendars
|
||||
color="#ee2c37"
|
||||
confirmColor="#ee2c37"
|
||||
ref="calendars"
|
||||
@confirm="calendarsConfirm"
|
||||
:endDate="endDate"
|
||||
:date="form.date"
|
||||
/>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import TitleComp from '@/components/title-comp/index'
|
||||
import { addUnit, sys } from '@climblee/uv-ui/libs/function/index'
|
||||
import { computed, ref, onBeforeMount, reactive, onMounted, watch } from 'vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { add } from '@/utils/index'
|
||||
import checkPermission from '@/utils/permission'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
const calendars = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const userStore = useUserStore()
|
||||
|
||||
const userInfo = computed(() => userStore.userInfo || {})
|
||||
const store = computed(() => userInfo.value.store)
|
||||
const endDate = timeFormat(new Date(), 'yyyy-mm-dd')
|
||||
|
||||
const form = reactive({
|
||||
date: endDate,
|
||||
items: [],
|
||||
new_customers: '',
|
||||
sales: '',
|
||||
expenditure: '',
|
||||
handover_amount: '',
|
||||
photos: [],
|
||||
})
|
||||
const rules = reactive({
|
||||
date: {
|
||||
required: true,
|
||||
message: '请选择日期',
|
||||
trigger: ['change'],
|
||||
},
|
||||
handover_amount: {
|
||||
required: true,
|
||||
message: '请输入交账金额',
|
||||
trigger: ['change'],
|
||||
},
|
||||
photos: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: '请上传时段报表照片',
|
||||
},
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
isBack: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
const style = computed(() => {
|
||||
const style = {}
|
||||
style.bottom = addUnit(sys().windowBottom, 'px')
|
||||
return style
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
getData(endDate)
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
const params = {
|
||||
date: form.date,
|
||||
sales: form.sales,
|
||||
expenditure: form.expenditure,
|
||||
handover_amount: form.handover_amount,
|
||||
new_customers: form.new_customers,
|
||||
photos: form.photos.map((item) => item.url),
|
||||
items: form.items,
|
||||
}
|
||||
http
|
||||
.request({
|
||||
url: '/ledgers',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
data: params,
|
||||
})
|
||||
.then((res) => {
|
||||
uni.$emit('revert:submit', res)
|
||||
getData()
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const resData = await http.get(`/ledgers/${form.date}`)
|
||||
|
||||
Object.assign(form, resData, {
|
||||
photos:
|
||||
resData?.photos?.map((item) => {
|
||||
return { url: item }
|
||||
}) || [],
|
||||
})
|
||||
}
|
||||
|
||||
const getTypeList = () => {
|
||||
http
|
||||
.get('/keywords', {
|
||||
params: {
|
||||
parent_key: 'lottery_type',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
form.items = res
|
||||
res.forEach((item, i) => {
|
||||
rules[`items.${i}.${'sales'}`] = {
|
||||
required: true,
|
||||
message: `请输入${item.name}销售金额`,
|
||||
}
|
||||
rules[`items.${i}.${'expenditure'}`] = {
|
||||
required: true,
|
||||
message: `请输入${item.name}兑奖金额`,
|
||||
}
|
||||
})
|
||||
console.log(rules)
|
||||
})
|
||||
}
|
||||
|
||||
const calendarsConfirm = (e) => {
|
||||
form.date = e.fulldate
|
||||
getData()
|
||||
}
|
||||
|
||||
const showDateSelect = () => {
|
||||
calendars.value.open()
|
||||
hideKeyboard()
|
||||
}
|
||||
|
||||
const hideKeyboard = () => {
|
||||
uni.hideKeyboard()
|
||||
}
|
||||
|
||||
const afterRead = async (event) => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = form[event.name].length
|
||||
|
||||
lists.map((item) => {
|
||||
form[event.name].push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中',
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFilePromise = (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http
|
||||
.upload('/fileupload', {
|
||||
filePath: url,
|
||||
name: 'file',
|
||||
})
|
||||
.then((res) => {
|
||||
resolve(res.url)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const deletePic = (event) => {
|
||||
form[event.name].splice(event.index, 1)
|
||||
}
|
||||
|
||||
const salesChange = () => {
|
||||
const val = form?.items || []
|
||||
const sales = val.reduce((a, b) => {
|
||||
return add(a, b?.sales ?? 0)
|
||||
}, 0)
|
||||
form.sales = sales || null
|
||||
}
|
||||
|
||||
const expenditureChange = () => {
|
||||
const val = form?.items || []
|
||||
const expenditure = val.reduce((a, b) => {
|
||||
return add(a, b?.expenditure ?? 0)
|
||||
}, 0)
|
||||
form.expenditure = expenditure || null
|
||||
}
|
||||
|
||||
watch(
|
||||
() => form.items,
|
||||
(val) => {
|
||||
const sales = val.reduce((a, b) => {
|
||||
return add(a, b?.sales ?? 0)
|
||||
}, 0)
|
||||
const expenditure = val.reduce((a, b) => {
|
||||
return add(a, b?.expenditure ?? 0)
|
||||
}, 0)
|
||||
// form.sales = sales || null
|
||||
// form.expenditure = expenditure || null
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="举报投诉"> </CuNavbar>
|
||||
<view class="space-y-base mt-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<uv-form
|
||||
labelWidth="160rpx"
|
||||
:borderBottom="false"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
ref="formRef"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-form-item label="投诉内容" prop="content">
|
||||
<uv-textarea
|
||||
maxlength="200"
|
||||
:customStyle="{ padding: 0 ,minHeight: '200rpx'}"
|
||||
count
|
||||
placeholder="可描述具体投诉内容,至少20字"
|
||||
:border="`none`"
|
||||
v-model="form.content"
|
||||
>
|
||||
</uv-textarea>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="" prop="photos">
|
||||
<view class="w-full">
|
||||
<view class="flex justify-between text-15px">
|
||||
<view>证明材料(选填)</view>
|
||||
<view class="text-hex-999999 text-12px pr-9px">{{form.photos.length}}/9</view>
|
||||
</view>
|
||||
<view class="mt-10rpx">
|
||||
<uv-upload
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交投诉?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import Cell from '@/components/cell/index'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const fileList = ref([])
|
||||
const form = reactive({
|
||||
content: '',
|
||||
photos: [],
|
||||
})
|
||||
const rules = reactive({
|
||||
content: [
|
||||
{ required: true, message: '可描述具体投诉内容,至少20字' },
|
||||
{ min: 20, message: '至少20字' },
|
||||
{ max: 200, message: '最多200字' },
|
||||
],
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const afterRead = async (event) => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = form[event.name].length
|
||||
|
||||
lists.map((item) => {
|
||||
form[event.name].push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中',
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
// console.log(lists[i]);
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
const deletePic = (event) => {
|
||||
form[event.name].splice(event.index, 1)
|
||||
}
|
||||
|
||||
const uploadFilePromise = (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http
|
||||
.upload('/fileupload', {
|
||||
filePath: url,
|
||||
name: 'file',
|
||||
})
|
||||
.then((res) => {
|
||||
resolve(res.url)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
http
|
||||
.post('/complaints', {
|
||||
content: form.content,
|
||||
photos: form.photos.map((item) => item.url),
|
||||
anonymous: true
|
||||
})
|
||||
.then((ress) => {
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="设置"></CuNavbar>
|
||||
<view class="space-y-base mt-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx">
|
||||
<Cell title="修改密码" :shadow="false" @onClick="goPath('/pages/setting/password')"></Cell>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<Cell title="举报投诉" :shadow="false" @click="goPath('/pages/setting/complain')"></Cell>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<Cell title="意见箱" :shadow="false" @click="goPath('/pages/setting/suggestion')"></Cell>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view>
|
||||
<Cell title="当前版本" :isLink="false">
|
||||
<view class="flex justify-end text-hex-999999 text-24rpx px-base">
|
||||
v{{ varsion }}
|
||||
</view>
|
||||
</Cell>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button block type="primary">退出登录</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import Cell from '@/components/cell/index'
|
||||
import { sys } from '@climblee/uv-ui/libs/function';
|
||||
import { computed } from 'vue';
|
||||
const sysInfo = sys()
|
||||
const varsion = computed(() => sysInfo.appVersion)
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="修改密码">
|
||||
<!-- <template #right>
|
||||
<view @click="submit" class="text-white text-24rpx">保存</view>
|
||||
</template> -->
|
||||
</CuNavbar>
|
||||
<view class="space-y-base mt-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<uv-form
|
||||
labelWidth="160rpx"
|
||||
labelPosition="left"
|
||||
:borderBottom="false"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
ref="formRef"
|
||||
>
|
||||
<uv-form-item label="新登录密码" prop="password">
|
||||
<uv-input
|
||||
border="none"
|
||||
input-align="right"
|
||||
type="password"
|
||||
v-model="form.password"
|
||||
placeholder="请输入新登录密码"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="新登录密码" prop="password2">
|
||||
<uv-input
|
||||
border="none"
|
||||
v-model="form.password2"
|
||||
input-align="right"
|
||||
type="password"
|
||||
placeholder="请输入新登录密码"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button type="primary" @click="submit">保存</uv-button>
|
||||
</view>
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定修改密码?"
|
||||
@confirm="changePassword"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import Cell from '@/components/cell/index'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const form = reactive({
|
||||
password: '',
|
||||
password2: '',
|
||||
})
|
||||
const rules = reactive({
|
||||
password: [{ required: true, message: '请输入新登录密码' }],
|
||||
password2: [
|
||||
{ required: true, message: '请输入新登录密码' },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
return value === form.password
|
||||
},
|
||||
message: '两次密码不一致',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const changePassword = () => {
|
||||
http
|
||||
.post('/auth/profile', {
|
||||
password: form.password,
|
||||
password_confirmation: form.password2,
|
||||
})
|
||||
.then((ress) => {
|
||||
uni.showToast({
|
||||
title: '修改成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="意见箱"> </CuNavbar>
|
||||
<view class="space-y-base mt-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<uv-form
|
||||
labelWidth="160rpx"
|
||||
:borderBottom="false"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
ref="formRef"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-form-item label="意见内容" prop="content">
|
||||
<uv-textarea
|
||||
maxlength="200"
|
||||
:customStyle="{ padding: 0 }"
|
||||
count
|
||||
placeholder="可描述具体意见内容,至少20字"
|
||||
border="none"
|
||||
v-model="form.content"
|
||||
>
|
||||
</uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交意见?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import Cell from '@/components/cell/index'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const form = reactive({
|
||||
content: '',
|
||||
})
|
||||
const rules = reactive({
|
||||
content: [
|
||||
{ required: true, message: '可描述具体意见内容,至少20字' },
|
||||
{ min: 20, message: '至少20字' },
|
||||
{ max: 200, message: '最多200字' },
|
||||
],
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
http
|
||||
.post('/feedback', {
|
||||
content: form.content,
|
||||
})
|
||||
.then((ress) => {
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<uv-scroll-list
|
||||
:indicator="true"
|
||||
indicatorColor="#fff0f0"
|
||||
indicatorActiveColor="#f56c6c"
|
||||
>
|
||||
<view>
|
||||
<template v-for="(item, i) in list" :key="i">
|
||||
<view v-if="i == 0" class="flex items-center w-full text-24rpx b-solid b-b-1px">
|
||||
<view class="w-140rpx text-center flex-none"> 日期 </view>
|
||||
<view class="w-300rpx text-center leading-60rpx flex-none b-r-solid b-r-1px b-l-solid b-l-1px">
|
||||
<view class="h-60rpx b-b-solid b-1px">总账</view>
|
||||
<view class="h-60rpx grid grid-cols-3">
|
||||
<view>销售</view>
|
||||
<view>支出</view>
|
||||
<view>新增客户</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="text-center leading-60rpx w-140rpx flex-none"
|
||||
v-for="(ty, j) in item.lottery_types"
|
||||
:key="j"
|
||||
>
|
||||
<view class="b-b-solid b-1px">{{ ty.name }}</view>
|
||||
<view class="grid grid-cols-2">
|
||||
<view>{{ ty.sales }}</view>
|
||||
<view>{{ ty.expenditure }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="flex justify-between text-center text-24rpx items-center card-shadow bg-white rounded-19rpx h-80rpx"
|
||||
>
|
||||
<view class="flex-1 w-140rpx flex-none">{{
|
||||
timeFormat(item.date, 'mm-dd')
|
||||
}}</view>
|
||||
<!-- 总账 -->
|
||||
<view class="flex-1">{{ item.ledger.sales }}</view>
|
||||
<view class="flex-1">{{ item.ledger.expenditure }}</view>
|
||||
<view class="flex-1">{{ item.ledger.new_customers }}</view>
|
||||
<!-- 种类 -->
|
||||
<template v-for="(ty, j) in item.lottery_types" :key="j">
|
||||
<view class="flex-1">{{ ty.sales }}</view>
|
||||
<view class="flex-1">{{ ty.expenditure }}</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</uv-scroll-list>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<view>
|
||||
<view
|
||||
class="flex justify-between text-center text-28rpx items-center h-80rpx"
|
||||
>
|
||||
<view class="flex-1">排名</view>
|
||||
<view class="flex-1">门店</view>
|
||||
<view class="flex-1">累计客户</view>
|
||||
<view class="flex-1">销售额</view>
|
||||
</view>
|
||||
<view
|
||||
class="flex justify-between text-center text-24rpx items-center bg-white rounded-19rpx h-80rpx"
|
||||
v-for="(item, i) in list"
|
||||
:key="i"
|
||||
>
|
||||
<view class="flex-1">{{ item.ranking }}</view>
|
||||
<view class="flex-1">{{ item.store.title }}</view>
|
||||
<view class="flex-1">{{ item.expenditure }}</view>
|
||||
<view class="flex-1">{{ item.sales }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="数据报表"></CuNavbar>
|
||||
<view>
|
||||
<uv-drop-down
|
||||
ref="dropDown"
|
||||
sign="dropDown_1"
|
||||
text-active-color="#3c9cff"
|
||||
:extra-icon="{ name: 'arrow-down-fill', color: '#666', size: '26rpx' }"
|
||||
:extra-active-icon="{
|
||||
name: 'arrow-up-fill',
|
||||
color: '#3c9cff',
|
||||
size: '26rpx',
|
||||
}"
|
||||
:defaultValue="['all', 'all']"
|
||||
:custom-style="{ padding: '0 30rpx' }"
|
||||
@click="selectMenu"
|
||||
>
|
||||
<uv-drop-down-item
|
||||
name="area"
|
||||
type="2"
|
||||
:label="dropDownData.area.label"
|
||||
:value="dropDownData.area.value"
|
||||
>
|
||||
</uv-drop-down-item>
|
||||
<uv-drop-down-item
|
||||
name="store"
|
||||
type="2"
|
||||
:label="dropDownData.store.label"
|
||||
:value="dropDownData.store.value"
|
||||
>
|
||||
</uv-drop-down-item>
|
||||
</uv-drop-down>
|
||||
</view>
|
||||
<view class="card">
|
||||
<uv-tabs
|
||||
:lineColor="'#ee2c37'"
|
||||
:list="tabsList"
|
||||
:scrollable="false"
|
||||
:current="tabIndex"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
|
||||
<view class="text-center text-28rpx" v-if="tabIndex != 0"
|
||||
>{{ currentTabs.start }} 至 {{ currentTabs.end }}
|
||||
</view>
|
||||
<view class="text-center text-28rpx" v-else>{{ currentTabs.start }}</view>
|
||||
<view class="flex my-20rpx items-center">
|
||||
<view class="text-center flex-1">
|
||||
<view>销售金额</view>
|
||||
<view class="font-600">{{ ledger.sales }}</view>
|
||||
</view>
|
||||
<view class="h-60rpx">
|
||||
<uv-line direction="col"></uv-line>
|
||||
</view>
|
||||
<view class="text-center flex-1">
|
||||
<view>兑奖金额</view>
|
||||
<view class="font-600">{{ ledger.sales }}</view>
|
||||
</view>
|
||||
<view class="h-60rpx">
|
||||
<uv-line direction="col"></uv-line>
|
||||
</view>
|
||||
<view class="text-center flex-1">
|
||||
<view>销售涨幅</view>
|
||||
<view class="text-primary font-600"
|
||||
>{{ ledger.sales_growth_rate }}%</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<uv-tabs
|
||||
@change="tabChange1"
|
||||
:lineColor="'#ee2c37'"
|
||||
:list="[{ name: '销售统计' }, { name: '门店统计' }]"
|
||||
:scrollable="false"
|
||||
:current="tabIndex1"
|
||||
></uv-tabs>
|
||||
<template v-if="tabIndex1 == 0">
|
||||
<List0 :list="list"></List0>
|
||||
</template>
|
||||
<template v-if="tabIndex1 == 1">
|
||||
<List1 :list="list"></List1>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import List0 from './components/list0.vue'
|
||||
import List1 from './components/list1.vue'
|
||||
const tabIndex1 = ref(0)
|
||||
const tabIndex = ref(0)
|
||||
const tabsList = ref(generateTimeArray())
|
||||
const list = ref([])
|
||||
const currentTabs = computed(() => tabsList.value[tabIndex.value])
|
||||
|
||||
const dropDownData = reactive({
|
||||
area: {
|
||||
label: '全部区域',
|
||||
value: 'all',
|
||||
activeIndex: 0,
|
||||
color: '#333',
|
||||
activeColor: '#2878ff',
|
||||
child: [
|
||||
{
|
||||
label: '全部区域',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
label: '重庆',
|
||||
value: 'cq',
|
||||
},
|
||||
{
|
||||
label: '北京',
|
||||
value: 'bj',
|
||||
},
|
||||
],
|
||||
},
|
||||
store: {
|
||||
label: '全部门店',
|
||||
value: 'all',
|
||||
activeIndex: 0,
|
||||
color: '#333',
|
||||
activeColor: '#2878ff',
|
||||
child: [
|
||||
{
|
||||
label: '全部门店',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
label: '门店1',
|
||||
value: 'new',
|
||||
},
|
||||
{
|
||||
label: '门店2',
|
||||
value: 'money',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const result = ref([])
|
||||
const ledger = ref({
|
||||
expenditure: '0',
|
||||
sales: '0',
|
||||
sales_growth_rate: '0',
|
||||
})
|
||||
|
||||
const activeName = ref('area')
|
||||
|
||||
onShow(() => {
|
||||
getCount()
|
||||
getList()
|
||||
})
|
||||
|
||||
const getCount = async () => {
|
||||
const resData = await http.get('/statistics/ledger', {
|
||||
params: {
|
||||
start_at: currentTabs.value.start,
|
||||
end_at: currentTabs.value.end,
|
||||
before_start_at: currentTabs.value.start,
|
||||
before_end_at: currentTabs.value.end,
|
||||
},
|
||||
})
|
||||
ledger.value = resData
|
||||
}
|
||||
|
||||
const selectMenu = (e) => {
|
||||
const { name, active, type } = e
|
||||
activeName.value = name
|
||||
const find = result.value.find((item) => item.name == activeName.value)
|
||||
if (find) {
|
||||
const findIndex = dropDownData[activeName.value].child.findIndex(
|
||||
(item) => item.label == find.label && item.value == find.value
|
||||
)
|
||||
dropDownData[activeName.value].activeIndex = findIndex
|
||||
} else {
|
||||
dropDownData[activeName.value].activeIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
function generateTimeRange(name, start, end) {
|
||||
start = timeFormat(start, 'yyyy-mm-dd')
|
||||
end = timeFormat(end, 'yyyy-mm-dd')
|
||||
return { name, start, end }
|
||||
}
|
||||
|
||||
function getStartOfWeek(date) {
|
||||
const dayOfWeek = date.getDay()
|
||||
const diff = date.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1) // 如果今天是周日,从上周一开始
|
||||
return new Date(date.setDate(diff))
|
||||
}
|
||||
|
||||
function getStartOfMonth(date) {
|
||||
return new Date(date.getFullYear(), date.getMonth(), 1)
|
||||
}
|
||||
|
||||
function generateTimeArray() {
|
||||
const today = new Date()
|
||||
const yesterday = new Date(today)
|
||||
yesterday.setDate(today.getDate() - 1)
|
||||
|
||||
const currentWeekStart = getStartOfWeek(today) // 获取本周第一天
|
||||
const currentWeekEnd = new Date(today)
|
||||
currentWeekEnd.setDate(currentWeekStart.getDate() + 6)
|
||||
|
||||
const lastWeekStart = new Date(currentWeekStart)
|
||||
lastWeekStart.setDate(currentWeekStart.getDate() - 7)
|
||||
const lastWeekEnd = new Date(currentWeekEnd)
|
||||
lastWeekEnd.setDate(currentWeekEnd.getDate() - 7)
|
||||
|
||||
const currentMonthStart = getStartOfMonth(today) // 获取本月第一天
|
||||
const currentMonthEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0)
|
||||
|
||||
const lastMonthStart = new Date(currentMonthStart)
|
||||
lastMonthStart.setMonth(lastMonthStart.getMonth() - 1)
|
||||
const lastMonthEnd = new Date(currentMonthEnd)
|
||||
lastMonthEnd.setMonth(lastMonthEnd.getMonth() - 1)
|
||||
|
||||
return [
|
||||
generateTimeRange('昨日', yesterday, yesterday),
|
||||
generateTimeRange('本周', currentWeekStart, currentWeekEnd),
|
||||
generateTimeRange('上周', lastWeekStart, lastWeekEnd),
|
||||
generateTimeRange('本月', currentMonthStart, currentMonthEnd),
|
||||
generateTimeRange('上月', lastMonthStart, lastMonthEnd),
|
||||
]
|
||||
}
|
||||
|
||||
const tabChange = (e) => {
|
||||
list.value = []
|
||||
tabIndex.value = e.index
|
||||
getCount()
|
||||
getList()
|
||||
}
|
||||
|
||||
const tabChange1 = (e) => {
|
||||
list.value = []
|
||||
tabIndex1.value = e.index
|
||||
getList()
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
const url = tabIndex1.value == 0 ? '/statistics/sales' : '/statistics/stores'
|
||||
const resData = await http.get(url, {
|
||||
params: {
|
||||
start_at: currentTabs.value.start,
|
||||
end_at: currentTabs.value.end,
|
||||
},
|
||||
})
|
||||
list.value = resData
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<view>1</view>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<view>1</view>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<view
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
@click.stop="onClick"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="text-30rpx">{{ item.name }}</view>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.taskable.status, item.taskable_type, 'color'),
|
||||
}"
|
||||
class="text-24rpx"
|
||||
>{{ statusFun(item.taskable.status, item.taskable_type, 'name') }}</view
|
||||
>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999">
|
||||
任务时间:{{ timeFormat(item.start_at, 'yyyy年mm月dd日') }} -
|
||||
{{ timeFormat(item.end_at, 'yyyy年mm月dd日') }}
|
||||
</view>
|
||||
<template v-if="item.taskable.status == 2">
|
||||
<view class="py-10rpx">
|
||||
<uv-line></uv-line>
|
||||
</view>
|
||||
<view class="flex justify-end">
|
||||
<view @click.stop="onTask">
|
||||
<uv-button type="primary" size="mini">去完成</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import statusFun from '@/utils/status'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const props = defineProps({
|
||||
item: Object,
|
||||
})
|
||||
|
||||
const onClick = () => {
|
||||
const type = props.item.taskable_type
|
||||
uni.navigateTo({
|
||||
url: `/pages/task/${type}_submit?id=${props.item.id}`,
|
||||
})
|
||||
}
|
||||
|
||||
const onTask = (e) => {
|
||||
const type = props.item.taskable_type
|
||||
uni.navigateTo({
|
||||
url: `/pages/task/${type}_submit?id=${props.item.id}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="任务详情"></CuNavbar>
|
||||
<view
|
||||
class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx"
|
||||
>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请人</view>
|
||||
<view class="text-hex-999999">测试人</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>所属门店</view>
|
||||
<view class="text-hex-999999">具体门店名称</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>电话号码</view>
|
||||
<view class="text-hex-999999">具体门店名称</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请时间</view>
|
||||
<view class="text-hex-999999">具体门店名称</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>申请范围</view>
|
||||
<view class="text-hex-999999 mt-20rpx">具体门店名称</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>清洁结果</view>
|
||||
<view class="text-hex-999999 mt-20rpx">
|
||||
<view class="bg-gray-50 b-solid w-130rpx h-130rpx"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-100rpx">
|
||||
<view
|
||||
class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx"
|
||||
>
|
||||
<view class="flex-1">
|
||||
<uv-button color="#999999" shape="circle" plain block> 拒绝 </uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block> 通过 </uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
</script>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="我的任务"></CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback">
|
||||
<view class="px-base space-y-20rpx mt-30rpx">
|
||||
<view
|
||||
v-for="item in 4"
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
>
|
||||
<view class="text-30rpx">月度清洁任务</view>
|
||||
<view class="text-24rpx text-hex-999999">
|
||||
任务时间:2022年03月01号 - 2022年03月31号
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999">待完成</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const list = ref([])
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '任务列表',
|
||||
apiUrl: '/tasks',
|
||||
},
|
||||
{
|
||||
name: '任务审核',
|
||||
apiUrl: '/workflow',
|
||||
params:{
|
||||
|
||||
}
|
||||
},
|
||||
])
|
||||
|
||||
const upCallback = async (mescroll) => {
|
||||
const { size, num } = mescroll
|
||||
|
||||
try {
|
||||
const resData = await http.get('/tasks', {
|
||||
params: {
|
||||
per_page: size,
|
||||
page: num,
|
||||
},
|
||||
})
|
||||
const curPageData = resData.data || []
|
||||
if (num === 1) list.value = []
|
||||
list.value = list.value.concat(curPageData)
|
||||
mescroll.endSuccess(curPageData.length)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
} finally {
|
||||
// firstloading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="我的任务"></CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
height="44"
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
:current="tabIndex"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:i="1"
|
||||
:top="88"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
></MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import Item from './components/item.vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '任务列表',
|
||||
apiUrl: '/tasks',
|
||||
},
|
||||
{
|
||||
name: '任务审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
// aaa:111
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="任务提交"> </CuNavbar>
|
||||
<view class="space-y-base mt-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<uv-form
|
||||
labelWidth="160rpx"
|
||||
:borderBottom="false"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
ref="formRef"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-form-item label="清洁范围" required prop="content">
|
||||
<uv-input
|
||||
:border="`bottom`"
|
||||
placeholder="请输入清洁范围"
|
||||
v-model="form.content"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="" prop="photos" required>
|
||||
<view class="w-full">
|
||||
<view class="flex justify-between text-15px">
|
||||
<view>清洁结果</view>
|
||||
<view class="text-hex-999999 text-12px pr-9px">0/9</view>
|
||||
</view>
|
||||
<view class="mt-10rpx">
|
||||
<uv-upload></uv-upload>
|
||||
</view>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交投诉?"
|
||||
@confirm="changePassword"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import Cell from '@/components/cell/index'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const form = reactive({
|
||||
content: '',
|
||||
photos: [],
|
||||
})
|
||||
const rules = reactive({
|
||||
content: [
|
||||
{ required: true, message: '请输入投诉内容' },
|
||||
{ min: 20, message: '至少20字' },
|
||||
{ max: 200, message: '最多200字' },
|
||||
],
|
||||
photos: {
|
||||
type: 'array',
|
||||
},
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const changePassword = () => {
|
||||
// http
|
||||
// .post('/auth/profile', {
|
||||
// password: form.password,
|
||||
// password_confirmation: form.password2,
|
||||
// })
|
||||
// .then((ress) => {
|
||||
// uni.showToast({
|
||||
// title: '修改成功',
|
||||
// duration: 2000,
|
||||
// icon: 'none',
|
||||
// })
|
||||
// formRef.value.resetFields()
|
||||
// })
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
<template>
|
||||
<view class="p-base">
|
||||
<CuNavbar title="清洁任务提交"></CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form
|
||||
labelPosition="left"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
errorType="toast"
|
||||
labelWidth="150rpx"
|
||||
>
|
||||
<uv-form-item required label="清洁范围" prop="description">
|
||||
<uv-input
|
||||
placeholder="请输入清洁范围"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.description"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
label="报销凭证"
|
||||
labelPosition="top"
|
||||
prop="photos"
|
||||
required
|
||||
>
|
||||
<view class="w-full mt-15rpx">
|
||||
<uv-upload
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交吗?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
const formRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
description: '',
|
||||
photos: [],
|
||||
})
|
||||
const rules = reactive({
|
||||
description: [{ required: true, message: '请输入清洁范围' }],
|
||||
photos: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: '请上传报销凭证',
|
||||
},
|
||||
})
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
await http.request({
|
||||
url: `/tasks/${id.value}/submit`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
data: {
|
||||
task_hygiene: {
|
||||
description: form.description,
|
||||
photos: form.photos.map((item) => item.url),
|
||||
},
|
||||
},
|
||||
})
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('task:submit', resData)
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const afterRead = async (event) => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = form[event.name].length
|
||||
|
||||
lists.map((item) => {
|
||||
form[event.name].push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中',
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFilePromise = (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http
|
||||
.upload('/fileupload', {
|
||||
filePath: url,
|
||||
name: 'file',
|
||||
})
|
||||
.then((res) => {
|
||||
resolve(res.url)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const deletePic = (event) => {
|
||||
form[event.name].splice(event.index, 1)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<template>
|
||||
<view>
|
||||
<RevertPage :isBack="true"></RevertPage>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import RevertPage from "@/pages/revert/index";
|
||||
</script>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="上传图片"></CuNavbar>
|
||||
<uv-upload></uv-upload>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar></CuNavbar>
|
||||
<!-- 文章 -->
|
||||
<template v-if="info.type == 1">
|
||||
<view class="h-400rpx">
|
||||
<uv-image width="100%" height="100%" :src="info.cover_image" />
|
||||
</view>
|
||||
</template>
|
||||
<!-- 视频 -->
|
||||
<template v-if="info.type == 2">
|
||||
<video class="w-full" :src="info.video" />
|
||||
</template>
|
||||
<view class="p-base space-y-10rpx">
|
||||
<view class="font-500 text-30rpx">{{ info.title }}</view>
|
||||
<view class="text-hex-999999">{{ info.description }}</view>
|
||||
<view class="text-hex-999 text-right">{{
|
||||
timeFormat(info.created_at)
|
||||
}}</view>
|
||||
</view>
|
||||
|
||||
<template v-if="info.type == 3">
|
||||
<view class="p-base space-y-8rpx">
|
||||
<view
|
||||
v-for="item in info.files"
|
||||
class="flex card-shadow bg-white rounded-19rpx p-base"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="line-clamp-1 flex-1">
|
||||
{{ item.name }}{{ item.name }}{{ item.name }}
|
||||
</view>
|
||||
<view @click="downloadFile(item.url)">
|
||||
<uv-icon size="40rpx" name="download"></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 富文本 -->
|
||||
<template v-if="info.content">
|
||||
<uv-divider />
|
||||
<view>
|
||||
<uv-parse :content="info.content"></uv-parse>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
|
||||
const id = ref('')
|
||||
const info = ref({})
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
http.get(`/train/books/${id.value}`).then((res) => {
|
||||
info.value = res
|
||||
})
|
||||
})
|
||||
|
||||
const downloadFile = (url) => {
|
||||
uni.downloadFile({
|
||||
url: url, // 文件的URL
|
||||
success: function (res) {
|
||||
console.log('下载成功', res)
|
||||
// 在这里可以处理文件下载后的操作,比如保存到本地、读取文件内容等
|
||||
},
|
||||
fail: function (err) {
|
||||
console.log('下载失败', err)
|
||||
// 在这里可以处理文件下载失败的情况,比如重新下载、提示用户等
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="培训课件"></CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
height="44"
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="true"
|
||||
:current="tabIndex"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
|
||||
<MescrollItem
|
||||
v-for="(item, key) in tabList"
|
||||
:key="item.id"
|
||||
:ref="`mescrollItem${item.id}`"
|
||||
:top="88"
|
||||
:i="key"
|
||||
:index="tabIndex"
|
||||
apiUrl="/train/books"
|
||||
:params="{ category_id: item.id }"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx mt-base">
|
||||
<template v-for="subItem in list" :key="subItem.id">
|
||||
<view
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
@click="detail(subItem.id)"
|
||||
>
|
||||
<view class="flex">
|
||||
<view
|
||||
v-if="subItem.cover_image"
|
||||
class="flex rounded-8rpx overflow-hidden"
|
||||
>
|
||||
<uv-image
|
||||
:src="subItem.cover_image"
|
||||
width="160rpx"
|
||||
height="160rpx"
|
||||
/>
|
||||
</view>
|
||||
<view
|
||||
class="ml-12rpx flex-1 flex flex-col justify-between space-y-10rpx"
|
||||
>
|
||||
<view class="text-26rpx font-500 line-clamp-2">{{
|
||||
subItem.title
|
||||
}}</view>
|
||||
<view class="text-24rpx text-hex-999999">{{
|
||||
subItem.description
|
||||
}}</view>
|
||||
<view class="text-22rpx text-hex-999999 text-right">{{
|
||||
timeFormat(subItem.created_at)
|
||||
}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
|
||||
const mescrollItems = ref([])
|
||||
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
let tabList = ref([])
|
||||
http
|
||||
.get('/keywords', { params: { parent_key: 'book_category' } })
|
||||
.then((res) => {
|
||||
tabList.value = res
|
||||
})
|
||||
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
|
||||
const detail = (id) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/train-books/detail?id=${id}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<view class="flex rounded-19rpx box-content card" @click="goPage(`/pages/user/detail?id=${item.id}`)">
|
||||
<view class="rounded-full w-100rpx h-100rpx overflow-hidden">
|
||||
<image class="w-full h-full" :src="item.avatar"></image>
|
||||
</view>
|
||||
<view class="flex-1 ml-20rpx flex flex-col justify-between">
|
||||
<view class="flex text-sm">
|
||||
<view>{{ item.name }}</view>
|
||||
<template v-if="item.jobs">
|
||||
<uv-tags
|
||||
v-for="job in item.jobs"
|
||||
class="ml-20rpx"
|
||||
:text="job.name"
|
||||
:key="job.id"
|
||||
plain
|
||||
size="mini"
|
||||
type="primary"
|
||||
></uv-tags>
|
||||
</template>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999">
|
||||
<view class="">电话:{{ item.phone }}</view>
|
||||
<view class="" v-if="item.store">门店:{{ item.store.address }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
const goPage = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
<template>
|
||||
<view class="p-base">
|
||||
<CuNavbar title="员工详情">
|
||||
<template #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-20rpx card-shadow px-base text-14px">
|
||||
<view class="flex justify-between items-center min-h-88rpx">
|
||||
<view class="text-hex-999">头像</view>
|
||||
<view class="w-80rpx h-80rpx rounded-full overflow-hidden">
|
||||
<image class="w-full h-full" :src="detail.avatar"></image>
|
||||
</view>
|
||||
</view>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<view class="flex justify-between items-center min-h-88rpx">
|
||||
<view class="text-hex-999">姓名</view>
|
||||
<view class="">{{ detail.name }}</view>
|
||||
</view>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<view class="flex justify-between items-center min-h-88rpx">
|
||||
<view class="text-hex-999">手机号</view>
|
||||
<view class="">{{ detail.phone }}</view>
|
||||
</view>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<view class="flex justify-between items-center min-h-88rpx">
|
||||
<view class="text-hex-999">门店</view>
|
||||
<view class="" v-if="detail.store">{{ detail.store.address }}</view>
|
||||
<view class="" v-else>无</view>
|
||||
</view>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
|
||||
<uv-action-sheet
|
||||
ref="actionSheet"
|
||||
:actions="actionlist"
|
||||
@select="select"
|
||||
cancelText="取消"
|
||||
>
|
||||
</uv-action-sheet>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
:title="modalOptin.title"
|
||||
:content="modalOptin.content"
|
||||
@confirm="modalOptin.confirm"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
const modalRef = ref(null)
|
||||
const modalOptin = reactive({
|
||||
title: '提示',
|
||||
content: '',
|
||||
confirm: () => {},
|
||||
})
|
||||
const actionSheet = ref(null)
|
||||
const id = ref(null)
|
||||
const detail = ref({})
|
||||
const actionlist = ref([
|
||||
{
|
||||
name: '编辑',
|
||||
value: 'edit',
|
||||
},
|
||||
{
|
||||
name: '离职',
|
||||
value: 'quit',
|
||||
},
|
||||
{
|
||||
name: '删除',
|
||||
value: 'delete',
|
||||
},
|
||||
])
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
getDetail()
|
||||
})
|
||||
|
||||
const getDetail = () => {
|
||||
http.get(`/hr/employee/${id.value}`).then((res) => {
|
||||
detail.value = res
|
||||
})
|
||||
}
|
||||
|
||||
const open = () => {
|
||||
actionSheet.value.open()
|
||||
}
|
||||
const select = (e) => {
|
||||
const { value } = e
|
||||
if (value === 'edit') {
|
||||
uni.navigateTo({
|
||||
url: `/pages/user/update?id=${id.value}`,
|
||||
})
|
||||
} else if (value === 'quit') {
|
||||
modalOptin.content = '是否确认离职该员工?'
|
||||
modalOptin.confirm = onQuick
|
||||
modalRef.value.open()
|
||||
} else if (value === 'delete') {
|
||||
modalOptin.content = '是否确认删除该员工?'
|
||||
modalOptin.confirm = onDelete
|
||||
modalRef.value.open()
|
||||
}
|
||||
}
|
||||
const onDelete = () => {
|
||||
http.delete(`/hr/employee/${id.value}`).then((res) => {
|
||||
uni.$emit('user:onRefresh')
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
uni.navigateBack()
|
||||
})
|
||||
}
|
||||
const onQuick = () => {
|
||||
http.post(`/hr/employee/${id.value}/leave`).then((res) => {
|
||||
uni.showToast({
|
||||
title: '离职成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
uni.$emit('user:onRefresh')
|
||||
uni.navigateBack()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="员工管理">
|
||||
<template #right>
|
||||
<text @click="goPage('/pages/user/update')" class="text-white"
|
||||
>添加</text
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<StoreDropDown></StoreDropDown>
|
||||
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback">
|
||||
<view class="mt-15rpx px-base">
|
||||
<!-- <uv-swipe-action> -->
|
||||
<view class="space-y-15rpx">
|
||||
<view
|
||||
class="rounded-19rpx card p-0 overflow-hidden"
|
||||
v-for="(item, i) in list"
|
||||
:key="i"
|
||||
@click="goPage(`/pages/user/detail?id=${item.id}`)"
|
||||
>
|
||||
<!-- <uv-swipe-action-item :options="options"> -->
|
||||
<view class="flex rounded-19rpx box-content card">
|
||||
<view class="rounded-4rpx w-100rpx h-100rpx">
|
||||
<image class="w-full h-full" :src="item.avatar"></image>
|
||||
</view>
|
||||
<view
|
||||
class="flex-1 ml-20rpx flex flex-col justify-between py-10rpx"
|
||||
>
|
||||
<view class="flex items-center text-sm">
|
||||
<view>{{ item.name }}</view>
|
||||
<template v-if="item.jobs">
|
||||
<uv-tags
|
||||
v-for="job in item.jobs"
|
||||
class="ml-20rpx"
|
||||
:text="job.name"
|
||||
:key="job.id"
|
||||
plain
|
||||
size="mini"
|
||||
type="primary"
|
||||
></uv-tags>
|
||||
</template>
|
||||
</view>
|
||||
<view class="flex justify-between">
|
||||
<view class="text-28rpx text-hex-999 text-xs">{{
|
||||
item.phone
|
||||
}}</view>
|
||||
<view v-if="item.store">{{ item.store.address }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- </uv-swipe-action-item> -->
|
||||
</view>
|
||||
</view>
|
||||
<!-- </uv-swipe-action> -->
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import StoreDropDown from '@/pages/home/components/store-drop-down/index.vue'
|
||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const firstloading = ref(true)
|
||||
const list = ref([])
|
||||
const options = [
|
||||
{
|
||||
text: '删除',
|
||||
style: {
|
||||
backgroundColor: '#f56c6c',
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '修改',
|
||||
style: {
|
||||
backgroundColor: '#3c9cff',
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '离职',
|
||||
style: {
|
||||
backgroundColor: '#f9ae3d',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
onShow(() => {
|
||||
if (!firstloading.value) {
|
||||
getMescroll().resetUpScroll()
|
||||
}
|
||||
})
|
||||
|
||||
const upCallback = async (mescroll) => {
|
||||
const { size, num } = mescroll
|
||||
|
||||
try {
|
||||
const resData = await http.get('/hr/employee', {
|
||||
params: {
|
||||
per_page: size,
|
||||
page: num,
|
||||
},
|
||||
})
|
||||
const curPageData = resData.data || []
|
||||
if (num === 1) list.value = []
|
||||
list.value = list.value.concat(curPageData)
|
||||
mescroll.endSuccess(curPageData.length)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
} finally {
|
||||
firstloading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const goPage = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="员工管理">
|
||||
<template #right>
|
||||
<text @click="goPage('/pages/user/update')" class="text-white"
|
||||
>添加</text
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<StoreDropDown></StoreDropDown>
|
||||
<MescrollApiOne
|
||||
:top="88"
|
||||
ref="mescrollItem"
|
||||
apiUrl="/hr/employee"
|
||||
:params="params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollApiOne>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import StoreDropDown from '@/pages/home/components/store-drop-down/index.vue'
|
||||
import Item from './components/item.vue'
|
||||
import MescrollApiOne from '@/components/mescroll-api/one'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollComp from '@/uni_modules/mescroll-uni/hooks/useMescrollComp.js'
|
||||
const { mescrollItem } = useMescrollComp(onPageScroll, onReachBottom)
|
||||
const params = ref(null)
|
||||
|
||||
onLoad(()=>{
|
||||
uni.$on('user:onRefresh',onRefresh)
|
||||
})
|
||||
|
||||
const onRefresh = () => {
|
||||
// params.value = {
|
||||
// city_code: 11,
|
||||
// store_id: 12,
|
||||
// }
|
||||
mescrollItem.value.getMescroll().resetUpScroll()
|
||||
}
|
||||
const goPage = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
<template>
|
||||
<view class="p-base">
|
||||
<CuNavbar :title="title">
|
||||
<!-- <template #right>
|
||||
<view class="text-white">保存</view>
|
||||
</template> -->
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form
|
||||
labelPosition="left"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
errorType="toast"
|
||||
labelWidth="150rpx"
|
||||
>
|
||||
<uv-form-item required label="姓名" prop="name">
|
||||
<uv-input
|
||||
placeholder="请输入姓名"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.name"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="手机号" prop="phone">
|
||||
<uv-input
|
||||
placeholder="请输入手机号"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
v-model="form.phone"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="登录用户名" prop="username">
|
||||
<uv-input
|
||||
placeholder="请输入登录用户名"
|
||||
inputAlign="right"
|
||||
v-model="form.username"
|
||||
:border="`none`"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item :required="!isEdit" label="登录密码" prop="password">
|
||||
<uv-input
|
||||
placeholder="请输入登录密码"
|
||||
inputAlign="right"
|
||||
type="password"
|
||||
v-model="form.password"
|
||||
:border="`none`"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item :required="!isEdit" label="门店" prop="password">
|
||||
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button type="primary" @click="submit">保存</uv-button>
|
||||
</view>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交员工信息?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { mobile } from '@climblee/uv-ui/libs/function/test'
|
||||
import { http } from '@/utils/request'
|
||||
const formRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
name: '',
|
||||
phone: '',
|
||||
username: '',
|
||||
password: '',
|
||||
confirm_password: '',
|
||||
})
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
name: [{ required: true, message: '请输入姓名' }],
|
||||
phone: [
|
||||
{ required: true, message: '请输入手机号' },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
return mobile(value)
|
||||
},
|
||||
message: '请输入正确的手机号',
|
||||
},
|
||||
],
|
||||
username: [{ required: true, message: '请输入登录用户名' }],
|
||||
password: [{ required: !isEdit.value, message: '请输入登录密码' }],
|
||||
confirm_password: [
|
||||
{ required: !isEdit.value, message: '请输入登录密码' },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
return form.password === value
|
||||
},
|
||||
message: '两次密码不一致',
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
if(isEdit.value) getDetail()
|
||||
})
|
||||
const isEdit = computed(() => !!id.value)
|
||||
const title = computed(() => (isEdit.value ? '员工修改' : '员工添加'))
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
if (isEdit.value) {
|
||||
updateUser()
|
||||
} else {
|
||||
addUser()
|
||||
}
|
||||
}
|
||||
const updateUser = async () => {
|
||||
if (loading.value) {
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
await http.put(`/hr/employee/${id.value}`, {
|
||||
...form,
|
||||
})
|
||||
uni.$emit('user:onRefresh')
|
||||
uni.navigateBack()
|
||||
formRef.value.resetFields()
|
||||
uni.showToast({
|
||||
title: '修改成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
const addUser = async () => {
|
||||
if (loading.value) {
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
await http.post('/hr/employee', {
|
||||
...form,
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.showToast({
|
||||
title: '添加成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getDetail = () => {
|
||||
http.get(`/hr/employee/${id.value}`).then((res) => {
|
||||
const info = {
|
||||
name: res.name,
|
||||
phone: res.phone,
|
||||
username: res.username,
|
||||
}
|
||||
Object.assign(form, info)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="升职申请">
|
||||
<template v-if="!isEdit" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="white">
|
||||
<view class="p-base box-shadow text-28rpx">
|
||||
<view class="flex justify-between px-10rpx">
|
||||
<view>晋升职位</view>
|
||||
<view>{{ detail?.job?.name }}</view>
|
||||
</view>
|
||||
<view class="flex justify-between mt-15rpx px-10rpx">
|
||||
<view>申请人</view>
|
||||
<view>{{ detail?.employee?.name }}</view>
|
||||
</view>
|
||||
<view class="flex justify-between mt-15rpx px-10rpx">
|
||||
<view>推荐人</view>
|
||||
<view>{{ detail?.invitor?.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<view class="p-base" :class="isEdit ? '' : 'pointer-events-none'">
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form
|
||||
labelPosition="left"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
errorType="toast"
|
||||
labelWidth="250rpx"
|
||||
>
|
||||
<uv-form-item :required="isEdit" label="年龄" prop="age">
|
||||
<uv-input
|
||||
placeholder="请输入年龄"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.age"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item :required="isEdit" label="性别" prop="sex">
|
||||
<uv-input
|
||||
placeholder="请选择性别"
|
||||
@click="openPicker"
|
||||
readonly
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.sex"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item :required="isEdit" label="学历" prop="education">
|
||||
<uv-input
|
||||
placeholder="请输入学历"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.education"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
:required="isEdit"
|
||||
label="首次参加工作时间"
|
||||
prop="first_work_time"
|
||||
>
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
:required="isEdit"
|
||||
@click="openDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.first_work_time"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item :required="isEdit" label="工作年限" prop="work_years">
|
||||
<uv-input
|
||||
placeholder="请输入工作年限"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.work_years"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
:required="isEdit"
|
||||
label="本公司工作年限"
|
||||
prop="work_years_in_company"
|
||||
>
|
||||
<uv-input
|
||||
placeholder="请输入本公司工作年限"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.work_years_in_company"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
:required="isEdit"
|
||||
label="员工自评"
|
||||
prop="comment_self"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-textarea
|
||||
v-model="form.comment_self"
|
||||
count
|
||||
placeholder="请输入员工自评"
|
||||
:border="`none`"
|
||||
:maxlength="200"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
:required="isEdit"
|
||||
label="未来计划"
|
||||
prop="plans"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-textarea
|
||||
v-model="form.plans"
|
||||
count
|
||||
placeholder="请输入未来计划"
|
||||
:border="`none`"
|
||||
:maxlength="200"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
<template v-if="detail.promotion_status > 1">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
label="推荐理由"
|
||||
prop="reason"
|
||||
:required="isEdit"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-textarea
|
||||
v-model="form.reason"
|
||||
count
|
||||
placeholder="请输入推荐理由"
|
||||
:border="`none`"
|
||||
:maxlength="200"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
</template>
|
||||
</uv-form>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="px-base" v-if="isEdit">
|
||||
<view class="py-30rpx">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-picker
|
||||
ref="pickerRef"
|
||||
:columns="columns"
|
||||
@confirm="confirmPicker"
|
||||
></uv-picker>
|
||||
<uv-datetime-picker
|
||||
:minDate="50"
|
||||
placeholder="请选择日期"
|
||||
ref="datetimePicker"
|
||||
mode="year-month"
|
||||
@confirm="confirmDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交吗?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
|
||||
<uv-action-sheet
|
||||
ref="actionSheet"
|
||||
:actions="actionlist"
|
||||
@select="select"
|
||||
cancelText="取消"
|
||||
>
|
||||
</uv-action-sheet>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref, reactive, computed, onBeforeMount } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: [Number, String],
|
||||
},
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
},
|
||||
})
|
||||
const actionlist = ref([
|
||||
{
|
||||
name: '去提交',
|
||||
value: 'submit',
|
||||
},
|
||||
])
|
||||
const actionSheet = ref(null)
|
||||
const columns = [['男', '女']]
|
||||
const formRef = ref(null)
|
||||
const datetimePicker = ref(null)
|
||||
const pickerRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const loading = ref(false)
|
||||
const detail = ref({})
|
||||
|
||||
const form = reactive({
|
||||
age: '',
|
||||
sex: '',
|
||||
education: '',
|
||||
first_work_time: '',
|
||||
work_years: '',
|
||||
work_years_in_company: '',
|
||||
comment_self: '',
|
||||
plans: '',
|
||||
reason: '',
|
||||
})
|
||||
const openPicker = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const openDatePicker = () => {
|
||||
datetimePicker.value.open()
|
||||
}
|
||||
const confirmDatePicker = (e) => {
|
||||
form.first_work_time = timeFormat(e.value, 'yyyy-mm')
|
||||
}
|
||||
const confirmPicker = (e) => {
|
||||
form.sex = e.value[0]
|
||||
}
|
||||
const rules = reactive({
|
||||
age: [{ required: true, message: '请输入年龄' }],
|
||||
sex: [{ required: true, message: '请选择性别' }],
|
||||
education: [{ required: true, message: '请输入学历' }],
|
||||
first_work_time: [{ required: true, message: '请输入首次参加工作时间' }],
|
||||
work_years: [{ required: true, message: '请输入清洁范围' }],
|
||||
work_years_in_company: [{ required: true, message: '请输入本公司工作年限' }],
|
||||
comment_self: [{ required: true, message: '请输入员工自评' }],
|
||||
plans: [{ required: true, message: '请输入未来计划' }],
|
||||
reason: [{ required: true, message: '请输入推荐理由' }],
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
getDetail()
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
...form,
|
||||
}
|
||||
const resData = await http.request({
|
||||
url: `/hr/promotion/${props.id}/apply`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
data: params,
|
||||
})
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('work:submit', resData)
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getDetail = async () => {
|
||||
http.get(`/hr/promotion/${props.id}`).then((res) => {
|
||||
detail.value = res
|
||||
Object.assign(form, res?.employee_data || {})
|
||||
})
|
||||
}
|
||||
|
||||
const open = () => {
|
||||
actionSheet.value.open()
|
||||
}
|
||||
|
||||
const select = (e) => {
|
||||
const { value } = e
|
||||
if(value === 'submit') {
|
||||
uni.navigateTo({
|
||||
url: `/pages/work/create?id=${props.id}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<view
|
||||
@click="onClick"
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="text-30rpx"> {{ item.job.name }}</view>
|
||||
<view
|
||||
class="text-24rpx"
|
||||
:style="{
|
||||
color: statusFun(item.promotion_status, 'promotion_status', 'color'),
|
||||
}"
|
||||
>{{ item.promotion_status_text }}</view
|
||||
>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="w-140rpx">推荐人</view>
|
||||
<view class="">{{ item?.invitor?.name }}</view>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="w-140rpx">晋升职位</view>
|
||||
<view class="">{{ item.job.name }}</view>
|
||||
</view>
|
||||
|
||||
<!-- <template v-if="options?.includes(item.promotion_status)">
|
||||
<view class="py-10rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="flex justify-end items-center">
|
||||
<uv-button type="primary" size="mini">去提交</uv-button>
|
||||
</view>
|
||||
</template> -->
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import statusFun from '@/utils/status'
|
||||
const props = defineProps({
|
||||
item: Object,
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
type: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
subject_type: String,
|
||||
})
|
||||
|
||||
const onOption = (e) => {}
|
||||
|
||||
const onClick = () => {
|
||||
let url
|
||||
if (props.type == 3) {
|
||||
} else {
|
||||
url = `/pages/work/detail?id=${props.item.id}`
|
||||
}
|
||||
goPath(url)
|
||||
}
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<view>
|
||||
<commone :id="id" isEdit></commone>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import commone from './commone.vue'
|
||||
import { ref } from 'vue'
|
||||
const id = ref(0)
|
||||
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<template>
|
||||
<view>
|
||||
<commone :id="id"></commone>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import commone from './commone.vue'
|
||||
import { ref } from 'vue'
|
||||
const id = ref(0)
|
||||
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="升职申请"> </CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :type="0" :item="item" :options="[1]"> </Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :type="1" :item="item" :options="[2]"> </Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem2"
|
||||
:top="88"
|
||||
:i="2"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[2].apiUrl"
|
||||
:params="tabList[2].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item
|
||||
:type="2"
|
||||
:subject_type="tabList[2].params.subject_type"
|
||||
:item="item"
|
||||
></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import Item from './components/item.vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '申请列表',
|
||||
apiUrl: '/hr/promotion/apply',
|
||||
},
|
||||
{
|
||||
name: '推荐列表',
|
||||
apiUrl: '/hr/promotion/apply',
|
||||
},
|
||||
{
|
||||
name: '审核列表',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'employee_promotions',
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
const mescrollItem2 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1, mescrollItem2]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('work:submit', getMescroll(tabIndex.value))
|
||||
})
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export {};
|
||||
|
||||
declare module "vue" {
|
||||
type Hooks = App.AppInstance & Page.PageInstance;
|
||||
interface ComponentCustomOptions extends Hooks {}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 0px 16px 0px rgba(0, 0, 0, 0.04);
|
||||
border-radius: 10px;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.card-shadow {
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 0px 16px 0px rgba(0, 0, 0, 0.04);
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.box-shadow {
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 0px 16px 0px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// 此文件为uvUI的主题变量,这些变量目前只能通过uni.scss引入才有效,另外由于
|
||||
// uni.scss中引入的样式会同时混入到全局样式文件和单独每一个页面的样式中,造成微信程序包太大,
|
||||
// 故uni.scss只建议放scss变量名相关样式,其他的样式可以通过main.js或者App.vue引入
|
||||
|
||||
$uv-main-color: #303133;
|
||||
$uv-content-color: #606266;
|
||||
$uv-tips-color: #909193;
|
||||
$uv-light-color: #c0c4cc;
|
||||
$uv-border-color: #dadbde;
|
||||
$uv-bg-color: #f3f4f6;
|
||||
$uv-disabled-color: #c8c9cc;
|
||||
|
||||
$uv-primary: #ee2c37;
|
||||
$uv-primary-dark: #398ade;
|
||||
$uv-primary-disabled: #9acafc;
|
||||
$uv-primary-light: #ecf5ff;
|
||||
|
||||
$uv-warning: #f9ae3d;
|
||||
$uv-warning-dark: #f1a532;
|
||||
$uv-warning-disabled: #f9d39b;
|
||||
$uv-warning-light: #fdf6ec;
|
||||
|
||||
$uv-success: #5ac725;
|
||||
$uv-success-dark: #53c21d;
|
||||
$uv-success-disabled: #a9e08f;
|
||||
$uv-success-light: #f5fff0;
|
||||
|
||||
$uv-error: #f56c6c;
|
||||
$uv-error-dark: #e45656;
|
||||
$uv-error-disabled: #f7b2b2;
|
||||
$uv-error-light: #fef0f0;
|
||||
|
||||
$uv-info: #909399;
|
||||
$uv-info-dark: #767a82;
|
||||
$uv-info-disabled: #c4c6c9;
|
||||
$uv-info-light: #f4f4f5;
|
||||
|
||||
@mixin flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: $direction;
|
||||
}
|
||||
|
||||
.uv-navbar--fixed{
|
||||
z-index: 1000 !important;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>home3_icon_back_def</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="icon" transform="translate(-48.000000, -215.000000)">
|
||||
<g id="home3_icon_back_def" transform="translate(48.000000, 215.000000)">
|
||||
<rect id="矩形" fill="#000000" fill-rule="nonzero" opacity="0" x="0" y="0" width="28" height="28"></rect>
|
||||
<g id="back" transform="translate(13.500000, 14.500000) scale(-1, 1) translate(-13.500000, -14.500000) translate(6.000000, 8.000000)" stroke="#333333" stroke-linecap="round" stroke-width="2">
|
||||
<path d="M5,10 L8.59692142,5.91374903 C9.91060843,4.42134644 12.1853935,4.27646884 13.6777961,5.59015586 C13.7456217,5.64985929 13.8111753,5.71209516 13.8743179,5.77673125 L18,10 L18,10" id="路径-5" stroke-linejoin="round" transform="translate(11.500000, 6.500000) rotate(-270.000000) translate(-11.500000, -6.500000) "></path>
|
||||
<line x1="0" y1="6.5" x2="8" y2="6.5" id="直线-3"></line>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>home3_icon_back_def</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="icon" transform="translate(-48.000000, -215.000000)">
|
||||
<g id="home3_icon_back_def" transform="translate(48.000000, 215.000000)">
|
||||
<rect id="矩形" fill="#fff" fill-rule="nonzero" opacity="0" x="0" y="0" width="28" height="28"></rect>
|
||||
<g id="back" transform="translate(13.500000, 14.500000) scale(-1, 1) translate(-13.500000, -14.500000) translate(6.000000, 8.000000)" stroke="#fff" stroke-linecap="round" stroke-width="2">
|
||||
<path d="M5,10 L8.59692142,5.91374903 C9.91060843,4.42134644 12.1853935,4.27646884 13.6777961,5.59015586 C13.7456217,5.64985929 13.8111753,5.71209516 13.8743179,5.77673125 L18,10 L18,10" id="路径-5" stroke-linejoin="round" transform="translate(11.500000, 6.500000) rotate(-270.000000) translate(-11.500000, -6.500000) "></path>
|
||||
<line x1="0" y1="6.5" x2="8" y2="6.5" id="直线-3"></line>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>me_icon_more_def</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="icon" transform="translate(-238.000000, -264.000000)">
|
||||
<g id="me_icon_more_def" transform="translate(238.000000, 264.000000)">
|
||||
<rect id="矩形" x="0" y="0" width="14" height="14"></rect>
|
||||
<g id="编组-9" transform="translate(0.000000, 1.000000)" stroke="#333333" stroke-linecap="round">
|
||||
<path d="M4.5,9.5 L7.97809825,5.21946514 C9.02292793,3.93358143 10.9123445,3.73816853 12.1982282,4.78299821 C12.3183328,4.88058781 12.4307062,4.98732445 12.5343422,5.10225239 L16.5,9.5 L16.5,9.5" id="路径-5" stroke-linejoin="round" transform="translate(10.500000, 6.000000) rotate(-270.000000) translate(-10.500000, -6.000000) "></path>
|
||||
<line x1="0.5" y1="6" x2="7.5" y2="6" id="直线"></line>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue