123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- <template>
- <view>
- <!-- head -->
- <view class="head-area" :style="{ height: `${headHeight}rpx` }">
- <u-navbar
- :is-fixed="false"
- :border-bottom="false"
- :is-back="true"
- :custom-back="navBack"
- :title="isWeixin ? '' : option.navTitle"
- :back-icon-name="option.navBackIcon || 'arrow-leftward'"
- back-icon-color="#fff"
- back-icon-size="35"
- :background="{ background: 'transparent' }"
- title-color="#fff"
- >
- <view class="nav-title" v-if="isWeixin">{{ option.navTitle }}</view>
- <view class="nav-right" slot="right" v-if="option.manageBtn" @click="manageSwitch = !manageSwitch">
- {{ manageSwitch ? '完成' : '管理' }}
- </view>
- </u-navbar>
- <view class="search-item" v-if="option.searchShow">
- <u-search
- placeholder="搜索内容"
- v-model="searchValue"
- @search="onSearch(searchValue)"
- @clear="onSearch(searchValue)"
- shape="square"
- bg-color="#8EAAFF"
- placeholder-color="#5470C4"
- color="#fff"
- search-icon-color="#ffffffE5"
- :clearabled="true"
- :show-action="false"
- ></u-search>
- </view>
- </view>
- <!-- head seat -->
- <view :style="{ height: `${headHeight}rpx` }"></view>
- <!-- list -->
- <block v-if="data && data.length > 0">
- <view class="" v-for="(item, index) in data" :key="index">
- <crud-item
- :ref="`crud-item${index}`"
- :list="data"
- :node="item"
- :option="option"
- :nodeIndex="index"
- :checkList="checkList"
- :checkShow="manageSwitch"
- :random-num="randomNum"
- ></crud-item>
- </view>
- <view style="padding: 20rpx 0;"><slot name="loadmore"></slot></view>
- </block>
- <!-- foot -->
- <block v-if="manageSwitch">
- <view :style="[{ height: isFullSucreen ? '168rpx' : '100rpx' }]"></view>
- <view class="foot flex" v-if="manageSwitch" :class="[isFullSucreen ? 'foot-ipx' : '']">
- <checkbox-group @change="onCheckedAll">
- <label class="well-check flex flex-c">
- <checkbox
- color="#fff"
- style="transform: scale(0.7)"
- value="allSelect"
- :checked="checkedAll"
- class="curdCheck"
- ></checkbox>
- <text class="checkAll">全选 ({{ checkList.length }})</text>
- </label>
- </checkbox-group>
- <view class=""><view class="foot-del-btn" @click="onRemove">删除</view></view>
- </view>
- </block>
- <!-- form -->
- <u-popup
- v-model="createShow"
- safe-area-inset-bottom
- border-radius="14"
- mode="bottom"
- closeable
- @close="onCreateClose"
- :mask-close-able="false"
- >
- <view class="popup-head"><u-section :title="action" :right="false" line-color="#5f88ff"></u-section></view>
- <scroll-view scroll-y="true" style="height: 68vh;">
- <view class="form">
- <block v-if="formType == 'uviewForm'">
- <u-form :model="value" ref="uForm" :label-width="option.labelWidth || 160"><slot name="form"></slot></u-form>
- </block>
- <block v-else><slot name="form"></slot></block>
- </view>
- </scroll-view>
- <view class="form-btn">
- <u-button
- v-if="action != '查看'"
- @click="onSubmit"
- :loading="disabled"
- shape="circle"
- ripple
- :custom-style="{ width: '100%', background: 'linear-gradient(90deg, #69b0ff, #5f88ff)', color: '#fff' }"
- >
- 保存
- </u-button>
- </view>
- </u-popup>
- <!-- addBtn -->
- <movable-area class="movable-area">
- <movable-view class="movable-view" :x="moveX" :y="moveY" direction="all">
- <image src="@/static/images/crud/create.png" @click="onCreateOpen"></image>
- </movable-view>
- </movable-area>
- <!-- empty -->
- <slot name="empty">
- <block v-if="data.length == 0">
- <u-empty text="工作再忙,也要记得喝水~" margin-top="200" :src="require('@/static/images/crud/empty.png')"></u-empty>
- </block>
- </slot>
- </view>
- </template>
- <script>
- import crudItem from './components/crud-item/index'
- import { checkModel } from './util/tool.js'
- import validate from './util/validate.js'
- export default {
- name: 'rider-crud',
- components: { crudItem },
- props: {
- value: {}, // 表单
- data: Array, // 列表
- // 配置
- option: {
- type: Object,
- default: {
- column: []
- }
- },
- // 表单类型
- formType: {
- type: String,
- default: 'uviewForm'
- },
- // 返回事件
- navBack: {
- type: Function,
- default: null
- },
- rules: {}, // 校验规则
- readonly: {
- type: Boolean,
- default: false
- }
- },
- data() {
- return {
- isFullSucreen: checkModel(),
- moveX: 320, //添加按钮坐标
- moveY: 580,
- checkedAll: false, //全选
- checkList: [], //选中值
- createShow: false, //form弹窗
- disabled: false, // 操作按钮
- action: '新增',
- searchValue: '',
- isWeixin: false,
- manageSwitch: false,
- headHeight: 0,
- randomNum: Math.round(Math.random() * 99999) // 随机数,防止uni.on重复调用
- }
- },
- watch: {
- manageSwitch: {
- handler(newVal, oldVal) {
- this.checkList = []
- this.checkedAll = false
- },
- deep: true,
- immediate: true
- },
- 'option.searchShow': {
- handler(newVal, oldVal) {
- const that = this
- this.headHeight = newVal ? 192 : 98
- // #ifndef H5
- uni.getSystemInfo({
- success: function(res) {
- const statusBarHeight = Number(res.statusBarHeight) + Number(res.platform == 'ios' ? 44 : 48)
- that.headHeight = newVal ? statusBarHeight + 192 : statusBarHeight + 98
- }
- })
- // #endif
- },
- deep: true,
- immediate: true
- }
- },
- // 通信事件
- created() {
- let that = this
- uni.$on(`action${this.randomNum}`, ({ index }, i, list) => {
- that.onActionClick({ index }, i, list)
- })
- uni.$on(`checked${this.randomNum}`, (e, id) => {
- that.onChecked(e, id)
- })
- // #ifdef MP-WEIXIN
- this.isWeixin = true
- // #endif
- // #ifndef MP-WEIXIN
- this.isWeixin = false
- // #endif
- },
- methods: {
- setLazyLoad(func) {
- this.option.lazyLoad = func
- setTimeout(() => {
- this.data.forEach((d, i) => {
- this.$refs[`crud-item${i}`][0].setLazyLoad(func)
- })
- }, 100)
- },
- // 选择
- onChecked(e, id) {
- const i = e.detail.value[0]
- if (i) this.checkList.push(i)
- else this.checkList.splice(this.checkList.findIndex(e => e === id), 1)
- this.checkedAll = this.checkList.length === this.data.length
- },
- // 全选
- onCheckedAll() {
- if (!this.checkedAll) {
- this.checkedAll = true
- this.checkList = []
- this.data.map(e => {
- this.checkList.push(e.id)
- })
- } else {
- this.checkedAll = false
- this.checkList = []
- }
- },
- // 元素点击
- onClick(item, index) {
- const action = { name: '查看' }
- const data = JSON.parse(JSON.stringify(item))
- this.$emit('input', data)
- this.$emit('action-click', { index, data, actionIndex: -1, action, done: this.show })
- this.action = action.name
- },
- // 底部删除
- onRemove() {
- if (this.checkList.length === 0) {
- uni.showToast({
- title: '请选择至少一条数据',
- icon: 'none',
- duration: 2000
- })
- return
- }
- this.$emit('del', this.checkList.join(','))
- },
- // 打开弹窗
- onCreateOpen() {
- this.action = '新增'
- this.$emit('action-click', { action: { name: this.action }, done: this.show })
- },
- // 关闭弹窗
- onCreateClose() {
- this.hide()
- },
- // 添加保存
- onSubmit() {
- this.disabled = true
- const data = JSON.parse(JSON.stringify(this.value))
- if (this.formType == 'uviewForm') {
- // #ifdef MP
- validate(this.value, this.rules)
- .then(() => {
- this.$emit('submit', data, this.action, this.unloading, this.hide)
- })
- .catch(() => {
- this.unloading()
- })
- // #endif
- // #ifndef MP
- this.$refs.uForm.validate(valid => {
- if (valid) {
- this.$emit('submit', data, this.action, this.unloading, this.hide)
- } else {
- this.unloading()
- }
- })
- // #endif
- } else {
- validate(this.value, this.rules)
- .then(() => {
- debugger
- this.$emit('submit', data, this.action, this.unloading, this.hide)
- })
- .catch(() => {
- this.unloading()
- })
- }
- },
- // 左滑按钮点击
- onActionClick({ index }, i, list) {
- let action
- if (index == -1) action = { name: '查看' }
- else action = this.option.actions[index]
- const data = JSON.parse(JSON.stringify(list[i]))
- if (['新增', '编辑', '查看'].includes(action.name)) this.$emit('input', data)
- this.$emit('action-click', { index: i, data, actionIndex: index, action, done: this.show })
- // this.action = action.name
- this.$set(this, 'action', action.name)
- },
- //全选删除后回调
- allCheckHide(val) {
- if (this.checkedAll) this.manageSwitch = val
- this.checkList = []
- },
- // 搜索
- onSearch(val) {
- this.$emit('search', val)
- },
- show() {
- this.createShow = true
- setTimeout(() => {
- if (this.rules && this.$refs['uForm'] && typeof this.$refs['uForm'].setRules == 'function') {
- this.$refs['uForm'].setRules(this.rules)
- }
- }, 100)
- },
- hide() {
- this.createShow = false
- this.disabled = false
- this.$emit('input', {})
- this.$emit('update:readonly', false)
- },
- unloading() {
- this.disabled = false
- },
- hideChildren() {
- this.data.forEach((d, i) => {
- this.$refs[`crud-item${i}`][0].hide()
- })
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .flex {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .flex-one {
- flex: 1;
- }
- .head-area {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- z-index: 999;
- width: 100%;
- background: url('/static/images/head_bg.png') no-repeat center bottom;
- background-size: 100% 100%;
- .nav-right {
- color: #fff;
- font-size: 30rpx;
- font-weight: normal;
- padding-right: 30rpx;
- }
- .nav-title {
- color: #fff;
- font-size: 32rpx;
- font-weight: normal;
- }
- .search-item {
- padding: 0 30rpx;
- }
- }
- .head-h {
- height: 200rpx;
- }
- /* 底部 */
- /* 适配 */
- .foot-ipx {
- bottom: 68rpx !important;
- }
- .foot-ipx::after {
- content: ' ';
- position: fixed;
- bottom: 0 !important;
- left: 0;
- right: 0;
- height: 68rpx !important;
- width: 100%;
- background: #fff;
- }
- .foot {
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 99;
- width: 100%;
- padding: 0 26rpx;
- height: 100rpx;
- background: #fff;
- border-top: 2px solid #eee;
- &-del-btn {
- width: 160rpx;
- height: 64rpx;
- line-height: 64rpx;
- font-size: 26rpx;
- // color: #fff;
- text-align: center;
- border-radius: 34px;
- // background: linear-gradient(180deg, #5f88ff, #69b0ff);
- color: #f56c6c;
- background: #fef0f0;
- }
- }
- .form {
- padding: 0 30rpx 20rpx;
- }
- .popup-head {
- padding: 36rpx 30rpx;
- border-bottom: 2rpx dashed #efefef;
- }
- .form-btn {
- margin: 30rpx;
- min-height: 80rpx;
- }
- .movable-area {
- height: 100vh;
- width: 100%;
- top: 0;
- position: fixed;
- pointer-events: none;
- .movable-view {
- width: 96rpx;
- height: 96rpx;
- pointer-events: auto;
- image {
- width: 96rpx;
- height: 96rpx;
- }
- }
- }
- </style>
|