跳至主要內容

iview 使用技巧

OrangBus大约 36 分钟

左侧菜单刷新失效

添加一个隐藏的路径:src/menu/home/service.js

{
    path: `${pre}lottery/prize`,
    title: '奖品设置',
    auth: ["hidden"]
}

vuex

获取值

import {mapActions} from "vuex";

methods: {
    ...mapActions("admin/user", ["load"]),

   getData(){
        let data = await this.load();
    this.provider = data.user; 
    }
}
load({state, dispatch}) {
    return new Promise(async resolve => {
        // store 赋值
        state.info = await dispatch('admin/db/get', {
            dbName: 'sys',
            path: 'user.info',
            defaultValue: {},
            user: true
        }, {root: true});  // 留意这里需要从root节点去找方法
        resolve(state.info);
    })
}

示例

import {getWebsiteInfo} from "@api/system";
import util from '@/libs/util';
import {Message} from 'view-design';

/**
 * 网站基本信息
 * */
export default {
	namespaced: true,
	state: {
		website: {},
	},
	
	actions: {
		getWebSite({state, commit, dispatch}, data) {
			getWebsiteInfo(data).then(async res => {
				Message.destroy();
				if (res.code === 200){
					// 更新vuex的信息
					await dispatch("admin/system/setWebsite", res.data,{root:true});
					// 本地存储 === localstorege
					await util.storage.set("website", res.data)
				}
			});
		},
		/**
		 * @description 持久化保存网站信息
		 * @param {Object} state vuex state
		 * @param {Object} dispatch vuex dispatch
		 * @param {*} info info
		 */
		setWebsite({state, dispatch}, data = {}) {
			return new Promise(async resolve => {
				// store 赋值
				state.website = data;
				// 持久化
				await dispatch('admin/db/set', {
					dbName: 'database',
					path: 'website',
					value: data,
				},{root:true});
				resolve(data);
			})
		}
	},
}

颜色

ui-color

enum("primary","primary-light","primary-dark","info","success","warning","error");

模板

抽屉提交

ui-drawer-submit

<Drawer
        title="Create"
        v-model="drawer"
        width="720"
        :mask-closable="false"
        :styles="styles"
        >
    content
    <div class="drawer-footer">
        <Button style="margin-right: 8px" @click="drawer = false">关闭</Button>
        <Button type="primary" @click="drawer = false" :loading="submitting">保存</Button>
    </div>
</Drawer>    
ui-drawer-data

drawer: false,
styles: {
    height: 'calc(100% - 55px)',
    overflow: 'auto',
    paddingBottom: '53px',
    position: 'static'
},
ui-drawer-css

<style>
    .demo-drawer-footer{
        width: 100%;
        position: absolute;
        bottom: 0;
        left: 0;
        border-top: 1px solid #e8e8e8;
        padding: 10px 16px;
        text-align: right;
        background: #fff;
    }
</style>

表格编辑

ui-tb-field

submitting: false, // 是否是提交状态
loading: false,
columns: [
    {
        type: 'selection',
        width: 60,
        align: 'center',
        show: true
    },
    {
        title: 'ID',
        key: 'id',
        minWidth: 140,
        show: false
    },
    {
        title: '角色名称',
        key: 'name',
        minWidth: 140,
        tooltip: true,
        show: true
    },
    {
        title: '创建时间',
        key: 'created_at',
        minWidth: 200,
        show: true
    },
    {
        title: '操作',
        key: 'action',
        slot: 'action',
        minWidth: 200,
        maxWidth: 200,
        align: 'center',
        fixed: 'right',
        show: true
    }
],
list: [], // 列表数据
selectedData: [], // 选择数据
page: 1, // 当前页码
limit: 10, // 每页条数
total: 0, // 总条数

ui-action-curd

<template slot-scope="{ row }" slot="action">
    <div @click.stop.prevent>
        <a type="text" @click="add(row.id)">添加</a>
        <Divider type="vertical"/>
        <a type="text" @click="edit(row.id)">编辑</a>
        <Divider type="vertical"/>
        <Poptip
                confirm
                :transfer="true"
                :title="`是否确定删除?`"
                @on-ok="del(row.id)">
            <a type="text">删除</a>
        </Poptip>
    </div>
</template>

ui-action-curd-js

add(row, index) {
    this.title = "添加";
    this.form = {};
    this.$model$ = true
},
edit(row, index) {
    this.title = row.name;
    this.form = cloneDeep(row);
    this.$model$ = true
},
del(row, index) {

},

表单

ui-form-field

keys: {},
form: {
    id: 0,
    name: "",
},
formRule: {
    name: [
        {required: true, message: '必填', trigger: 'blur'}
    ]
},

ui-field-init

this.keys = Object.keys(this.form);

网站Logo位置

src/layouts/basic-layout/header-logo/index.vue

表格模板

ui-tb

<Table
       ref="table"
       :columns="tableColumns"
       :data="list"
       :loading="loading"
       :size="tableSize"
       :transfer="true"
       :border="true"
       class="ivu-mt"
       @on-select="handleSelect"
       @on-select-cancel="handleSelectCancel"
       @on-select-all="handleSelectAll"
       @on-select-all-cancel="handleSelectAllCancel"
       >
    <template slot-scope="{ row,index }" slot="course">
        {{ row.course ? row.course.name : '无' }}
    </template>
    <template slot-scope="{ row, index }" slot="action">
        <a @click="follow(index)">跟进</a>
        <Divider type="vertical"/>
        <Dropdown @on-click="(name) => action(name, index)" :transfer="true">
            <a type="text">更多
                <Icon type="ios-arrow-down"/>
            </a>
            <DropdownMenu slot="list" trigger="hover" :transfer="true">
                <DropdownItem name="editArchive">编辑客户</DropdownItem>
                <DropdownItem divided name="delete">删除</DropdownItem>
            </DropdownMenu>
        </Dropdown>
    </template>
</Table>

ui-tb-fileds

loading: false,
tableSize:"smail",
list: [],
selectedData: [],
page: 1,
limit: 10,
total: 0,
columns: [
     {type: 'selection',width: 60,align: 'center',show: true},
     {title: '项目名称',key: 'name',minWidth: 200,show: true},
	 {title: '创建时间', key: 'created_at',minWidth: 170,show: true },
	 {title: '操作',slot: 'action',align: 'center', fixed: 'right', minWidth: 120,show: true}
 ],
   

ui-tb-col

{title: '项目名称',key: 'name',minWidth: 200,show: true},
{title: '创建时间', key: 'created_at',minWidth: 170,show: true },
{title: '操作',slot: 'action',align: 'center', fixed: 'right', minWidth: 120,show: true}

ui-tb-show

computed: {
    tableColumns () {
        const columns = [...this.columns];
        return columns.filter(item => item.show);
    }
}

ui-tb-default-methods

// 选中一项,将数据添加至已选项中
handleSelect (selection, row) {
    this.selectedData.push(row);
},
// 取消选中一项,将取消的数据从已选项中删除
handleSelectCancel (selection, row) {
    const index = this.selectedData.findIndex(item => item.id === row.id);
    this.selectedData.splice(index, 1);
},
// 当前页全选时,判断已选数据是否存在,不存在则添加
handleSelectAll (selection) {
    selection.forEach(item => {
        if (this.selectedData.findIndex(i => i.id === item.id) < 0) {
            this.selectedData.push(item);
        }
    });
},
// 取消当前页全选时,将当前页的数据(即 dataWithPage)从已选项中删除
handleSelectAllCancel () {
    this.selectedData = [];
},
// 清空所有已选项
handleClearSelect () {
    let ids = [];
    this.selectedData.forEach(item => {
        ids.push(item.id);
    })
    if (ids.length === 0) {
        return this.$Message.error('请选择数据');
    }
    this.$Modal.confirm({
        title: '删除提示',
        content: `是否删除?`,
        onOk: () => {
            customerDelete({ ids }).then(res => {
                this.$Message.success(res.msg);
                this.getData();
                this.selectedData = [];
            });
        }
    });
},

ui-table-templet

<template slot-scope="{ row,index }" slot="course">
    {{ row.course ? row.course.name : '无' }}
</template>
// ui-table-more

<template slot-scope="{ row, index }" slot="action">
    <a @click="follow(index)">跟进</a>
    <Divider type="vertical"/>
    <Dropdown @on-click="(name) => action(name, index)" :transfer="true">
        <a type="text">更多
            <Icon type="ios-arrow-down"/>
        </a>
        <DropdownMenu slot="list" trigger="hover" :transfer="true">
            <DropdownItem name="editArchive">编辑客户</DropdownItem>
            <DropdownItem divided name="delete">删除</DropdownItem>
        </DropdownMenu>
    </Dropdown>
</template>

表格增删改查

// ui-table-js-curd

全屏

ref="card"

tableFullscreen = false

handleFullscreen() {
     this.tableFullscreen = !this.tableFullscreen;
     if (this.tableFullscreen) {
         screenfull.request(this.$refs.card.$el);
     } else {
         screenfull.exit();
     }
 },

表格辅助

 <div class="ivu-inline-block ivu-fr">
                <Dropdown @on-click="handleChangeTableSize" trigger="click">
                    <Tooltip class="ivu-ml" content="密度" placement="top">
                        <i-link>
                            <Icon type="md-list"/>
                        </i-link>
                    </Tooltip>
                    <DropdownMenu slot="list">
                        <DropdownItem name="default" :selected="tableSize === 'default'">默认</DropdownItem>
                        <DropdownItem name="large" :selected="tableSize === 'large'">宽松</DropdownItem>
                        <DropdownItem name="small" :selected="tableSize === 'small'">紧凑</DropdownItem>
                    </DropdownMenu>
                </Dropdown>
                <Tooltip class="ivu-ml" :content="tableFullscreen ? '退出全屏' : '全屏'" placement="top">
                    <i-link @click.native="handleFullscreen">
                        <Icon
                            :custom="tableFullscreen ? 'i-icon i-icon-exit-full-screen' : 'i-icon i-icon-full-screen'"/>
                    </i-link>
                </Tooltip>
                <Tooltip class="ivu-ml" content="刷新" placement="top">
                    <i-link @click.native="getData">
                        <Icon custom="i-icon i-icon-refresh"/>
                    </i-link>
                </Tooltip>
                <Dropdown trigger="click">
                    <Tooltip class="ivu-ml" content="列设置" placement="top">
                        <i-link>
                            <Icon type="md-options"/>
                        </i-link>
                    </Tooltip>
                    <DropdownMenu slot="list">
                        <div class="ivu-p-8">列展示</div>
                        <Divider size="small" class="ivu-mt-8 ivu-mb-8"/>
                        <li class="ivu-dropdown-item" v-for="item in columns" :key="item.title" v-if="item.title"
                            @click="item.show = !item.show">
                            <Checkbox v-model="item.show"></Checkbox>
                            <span>{{ item.title }}</span>
                        </li>
                    </DropdownMenu>
                </Dropdown>
            </div>
// 改变表格尺寸
        handleChangeTableSize(size) {
            this.tableSize = size;
        },
        // 表格全屏
        handleFullscreen() {
            this.tableFullscreen = !this.tableFullscreen;
            if (this.tableFullscreen) {
                screenfull.request(this.$refs.card.$el);
            } else {
                screenfull.exit();
            }
        },
        // 刷新表格数据
        handleRefresh() {
            this.getData();
        },
        // 切换页码
        handleChangePage(page) {
            this.page = page;
            this.getData();
        },
        // 切换每页条数
        handleChangePageSize(size) {
            this.page = 1;
            this.limit = size;
            this.getData();
        },
        // 选中一项,将数据添加至已选项中
        handleSelect(selection, row) {
            this.selectedData.push(row);
        },
        // 取消选中一项,将取消的数据从已选项中删除
        handleSelectCancel(selection, row) {
            const index = this.selectedData.findIndex(item => item.id === row.id);
            this.selectedData.splice(index, 1);
        },
        // 当前页全选时,判断已选数据是否存在,不存在则添加
        handleSelectAll(selection) {
            selection.forEach(item => {
                if (this.selectedData.findIndex(i => i.id === item.id) < 0) {
                    this.selectedData.push(item);
                }
            });
        },
        // 清空所有已选项
        handleClearSelect() {
            this.selectedData = [];
        },
        // 查找单一用户信息
        handleGetUser(id) {
            return this.list.find(item => item.id === id);
        },

批量删除

html

 <!--批量删除-->
<Alert show-icon class="ivu-mt" v-if="selectedData.length > 0">
     <div v-font="14">
         已选择 <strong v-color="'#2d8cf0'">{{ selectedData.length }}</strong>条数据
         <a class="ivu-ml" @click="handleClearSelect">删除</a>
     </div>
</Alert>

js

handleClearSelect() {
    let ids = [];
    this.selectedData.forEach(item => {
        ids.push(item.id);
    })
    this.$Modal.confirm({
        title: '删除提示',
        content: `是否删除?`,
        onOk: () => {
            $method$({ids}).then(res => {
                this.$Message.success(res.msg);
                this.selectedData = [];
                this.getData();
            });
        }
    });
},

ui-header-html

<PageHeader
            back hidden-breadcrumb
            :tab-list="tabList"
            :title="title"
            :tab-active-key="tab"
            @on-back="backPage"
            @on-tab-change="changeTab"
        >
            <div slot="action">
                <ButtonGroup>
                    <Button>操作</Button>
                    <Button>操作</Button>
                </ButtonGroup>
                <Button type="primary">主操作</Button>
            </div>
            <div slot="content">
                <DescriptionList :col="2">
                    <Description term="申请人:">公孙离</Description>
                    <Description term="部门:">可视化架构组</Description>
                    <Description term="产品线:">View UI</Description>
                    <Description term="用途说明:">生产环境</Description>
                    <Description term="申请时间:">2019-05-05</Description>
                    <Description term="申请时长:">1年</Description>
                </DescriptionList>
            </div>
            <div slot="extra">
                <p style="color: #808695">状态</p>
                <p style="font-size: 24px">待审批</p>
            </div>
        </PageHeader>

        <Card dis-hover class="ivu-mt-8">
           
        </Card>
ui-header-data

title: "标题",
tab: "1",
tabList: [
{
label: '统计',
name: '1'
},
{
label: '排名',
name: '2'
}
]
ui-header-methods

// 返回页面
backPage() {

},
// 切换选项卡
changeTab(item) {
	this.tab = item.name;
}

描述

ui-des

<DescriptionList :col="2">
    <Description term="申请人:">公孙离</Description>
    <Description term="部门:">可视化架构组</Description>
    <Description term="产品线:">View UI</Description>
    <Description term="用途说明:">生产环境</Description>
    <Description term="申请时间:">2019-05-05</Description>
    <Description term="申请时长:">1年</Description>
</DescriptionList>

数字展示

ui-numberinfo


<Row>
    <Col span="8">
        <NumberInfo title="" sub-title="今日" sub-total="17.1"
                    status="up">
            <Numeral value="12321" format="0,0" slot="total"/>
        </NumberInfo>
    </Col>
    <Col span="8">
        <NumberInfo title="" sub-title="本月" sub-total="5.3"
                    status="down">
            <CountUp :end="50193" :duration="4" slot="total"/>
        </NumberInfo>
    </Col>
    <Col span="8">
        <NumberInfo title="" sub-title="累计" sub-total="17.1"
                    status="up">
            <Numeral value="12321" format="0,0" slot="total"/>
        </NumberInfo>
    </Col>
</Row>

按钮组

ui-btn-group

<ButtonGroup>
    <Button type="primary">L</Button>
    <Button>M</Button>
    <Button>M</Button>
    <Button type="dashed">R</Button>
</ButtonGroup>

时间戳-页面展示

ui-time-show

<Time :time="timestamp" type="$TYPE$"/>

enum("date","datetime")

过渡效果

ui-transition

<transition name="$NAME$">
   
</transition>

enum("ivu-anim-fade","ivu-anim-ease","ivu-anim-move-up","ivu-anim-move-down","ivu-anim-move-left","ivu-anim-move-right","ivu-anim-transition-drop","ivu-anim-slide-up","ivu-anim-slide-down","ivu-anim-slide-left","ivu-anim-slide-right")

头部导航

ui-pg-header



<div class="i-layout-page-header">
    <PageHeader
        title="搜索列表(文章)"
        hidden-breadcrumb
        :tab-list="tabList"
        :tab-active-key="tabKey"
        @on-tab-change="changeHeaderTab"
    >
        <div slot="content" class="ivu-mt ivu-mb" style="max-width: 500px;margin: 0 auto;">
            <Input search size="large" enter-button="搜索" placeholder="Enter something..." />
        </div>
    </PageHeader>
</div>

ui-pg-header-data-js


tabKey: 'article',
tabList: [
    {
        label: '文章',
        name: 'article'
    },
    {
        label: '项目',
        name: 'projects'
    },
    {
        label: '应用',
        name: 'apps'
    }
]
ui-pg-header-methods

vue父子组互相操作

<template>
    <div class="container">
        <Row :gutter="24">
            <Col span="24">
                <Card :bordered="false" dis-hover>
                    <div class="ui-flex ui-flex-align-center ui-flex-space-between">
                        <div
                            v-if="archive.id && archive.id !== 0"
                            class="ui-flex ui-flex-align-center text-pointer userName"
                            @click="archiveModal = true">
                            <h2 class="ivu-mr-8">{{ archive.name }}</h2>
                            <Tooltip content="" v-if="archive.sex == 1">
                                <Icon type="md-male" color="#2d8cf0"/>
                            </Tooltip>
                            <Tooltip content="" v-if="archive.sex == 2">
                                <Icon type="md-female" color="red"/>
                            </Tooltip>
                            <div class="ivu-ml">
                                <span>手机号:{{ archive.phone }}</span>
                            </div>
                            <div class="ivu-ml">
                                <span>民族:{{ archive.mz ? archive.mz : ' - ' }}</span>
                            </div>
                            <div class="ivu-ml">
                                <span>身份证:{{ archive.id_card ? archive.id_card : ' - ' }}</span>
                            </div>
                        </div>
                    </div>
                </Card>
                <!--                <ArchiveDetail :archive="archive" :col="4"></ArchiveDetail>-->
            </Col>
            <Col span="24" class="ivu-mt">
                <Card dis-hover>
                    <Button type="primary" size="default" @click="create">添加</Button>
                    <Table
                        ref="table"
                        :columns="columns"
                        :data="list"
                        :transfer="true"
                        :border="true"
                        :loading="loading"
                        class="ivu-mt"
                    >
                        <template slot-scope="{ row,index }" slot="title">
                            <Tooltip :content="row.title" :transfer="true">
                                <span> {{ row.title }}</span>
                            </Tooltip>
                        </template>

                        <template slot-scope="{ row,index }" slot="name">
                            {{ row.name }}
                            <Tooltip :transfer="true" content="" v-if="row.sex == 1">
                                <Icon type="md-male" color="primary"/>
                            </Tooltip>
                            <Tooltip :transfer="true" content="" v-if="row.sex == 2">
                                <Icon type="md-female" color="red"/>
                            </Tooltip>
                        </template>

                        <template slot-scope="{ row }" slot="sex">
                            <Tag color="cyan" v-if="row.mz != ''">{{ row.mz }}</Tag>
                        </template>

                        <template slot-scope="{ row }" slot="status">
                            <CustomerStatus :status="row.status"></CustomerStatus>
                        </template>

                        <template slot-scope="{ row }" slot="channel">
                            <span v-for="(item,index) in param.channel" :key="index" v-if="row.channel_id == item.id"
                                  :style="'color:'+item.color">{{ item.name }}</span>
                        </template>
                        <template slot-scope="{ row }" slot="yxd">
                            <Tag v-for="(item,index) in param.yxd" :key="index" :color="item.color"
                                 v-if="row.yxd_id == item.id">{{
                                    item.name
                                }}
                            </Tag>
                        </template>
                        <template slot-scope="{ row }" slot="hangye">
                            <Tag v-for="(item,index) in param.hanye" :key="index" :color="item.color"
                                 v-if="row.hangye_id == item.id">{{
                                    item.name
                                }}
                            </Tag>
                        </template>
                        <template slot-scope="{ row, index }" slot="action">
                            <a @click="follow(index)">跟进</a>
                        </template>
                    </Table>
                    <div class="ivu-mt ivu-text-center">
                        <Page
                            :total="total"
                            :current.sync="current"
                            show-total
                            show-sizer
                            :page-size="limit"
                            @on-page-size-change="handleChangePageSize"
                        />
                    </div>
                </Card>
            </Col>
        </Row>
        <!--跟进-->
        <Drawer
            title="客户跟进"
            v-model="followDrawer"
            width="1200"
            placement="right"
            :mask-closable="true"
            :closable="true"
        >
            <!--            <follow :customer="customer" :param="param" @setTypeResult="setTypeResult"></follow>-->
            <follow
                v-if="followDrawer"
                :theCustomer="customer"
                :param="param"
                @setTypeResult="setTypeResult"
                @apply="apply"
            ></follow>
        </Drawer>
        <!--追加线索-->
        <Modal
            title="追加线索"
            v-model="createModal"
            :fullscreen="false"
            :transfer="false"
            :draggable="true"
            :scrollable="true"
            :loading="createCreating"
            width="1000"
            @on-ok="confirmCreate"
        >
            <Form v-if="createModal" :model="form" :rules="formRules" :label-width="labelWidth"
                  :label-position="labelPosition"
                  ref="create">
                <Row :gutter="24" justify="start">
                    <Col v-bind="grid">
                        <FormItem label="咨询人类型" prop="name_type">
                            <Select v-model="form.name_type" placeholder="请选择">
                                <Option value="1" selected>本人</Option>
                                <Option value="2">代咨询</Option>
                            </Select>
                        </FormItem>
                    </Col>
                    <Col v-bind="grid">
                        <FormItem label="来源渠道" prop="channel_id">
                            <Select v-model="form.channel_id" placeholder="请选择">
                                <Option v-for="(item,index) in param.channel" :key="index"
                                        :value="(item.id).toString()">
                                    {{ item.name }}
                                </Option>
                            </Select>
                        </FormItem>
                    </Col>
                    <Col v-bind="grid">
                        <FormItem label="客户等级" prop="level_id">
                            <Select v-model="form.level_id" placeholder="请选择">
                                <Option v-for="(item,index) in param.level" :key="index" :value="(item.id).toString()">
                                    {{
                                        item.name
                                    }}
                                </Option>
                            </Select>
                        </FormItem>
                    </Col>
                    <Col v-bind="grid">
                        <FormItem label="意向度" prop="yxd_id">
                            <Select v-model="form.yxd_id" placeholder="请选择">
                                <Option v-for="(item,index) in param.yxd" :key="index" :value="(item.id).toString()">{{
                                        item.name
                                    }}
                                </Option>
                            </Select>
                        </FormItem>
                    </Col>
                    <Col span="24">
                        <FormItem label="项目类型" prop="sex">
                            <RadioGroup v-model="form.pro_type">
                                <!--<Radio :label="1">课程</Radio>-->
                                <Radio :label="2">自定义</Radio>
                            </RadioGroup>
                        </FormItem>
                    </Col>
                    <Col span="24" v-if="form.pro_type == 1">
                        <FormItem label="咨询课程" prop="course">
                            <Button type="primary" @click="courseAdd" ghost icon="md-add" class="ivu-mr">添加</Button>
                            <Table :transfer="true" :columns="Coursecolumns" :data="selectCourseData" class="ivu-mt"
                                   size="small"
                                   v-if="selectCourseData.length > 0">
                                <template slot-scope="{ row }" slot="method">
                                    <span v-for="(item,index) in courseParam.methodList"
                                          :key="index"
                                          v-if="item.type == row.method">{{ item.name }}</span>
                                    {{ row.method }}
                                </template>
                                <template slot-scope="{ row }" slot="price">
                                    <strong>{{ row.price }}</strong>/{{ row.undeline_price }}
                                </template>
                                <template slot-scope="{ row }" slot="teacher">
                                    <strong>{{ row.teacher_id }}</strong>
                                </template>
                                <template slot-scope="{ row }" slot="org_school">
                                    <strong>【{{ row.school ? row.school.name : '' }}】</strong>
                                    <span>{{ row.school ? row.school.org ? row.school.org.name : '' : '' }}</span>
                                </template>
                                <template slot-scope="{ row, index }" slot="action">
                                    <Poptip
                                        confirm
                                        :transfer="true"
                                        title="确定删除?"
                                        @on-ok="removeCourse(index)"
                                    >
                                        <Icon type="ios-trash-outline" color="red" size="24"/>
                                    </Poptip>
                                </template>
                            </Table>
                        </FormItem>
                    </Col>
                    <Col span="24" v-if="form.pro_type == 2">
                        <FormItem label="咨询项目" prop="title">
                            <Input v-model="form.title" type="textarea" :autosize="{minRows: 2,maxRows: 6}"
                                   placeholder="请输入咨询内容"></Input>
                        </FormItem>
                    </Col>
                    <Col span="24">
                        <FormItem label="咨询内容" prop="content">
                            <Input v-model="form.content" type="textarea" :autosize="{minRows: 4,maxRows: 8}"
                                   placeholder="请输入咨询内容"></Input>
                        </FormItem>
                    </Col>
                </Row>
            </Form>
        </Modal>

        <!--添加课程-->
        <Modal
            title="咨询课程"
            v-model="courseModal"
            :fullscreen="false"
            :transfer="false"
            width="1000"
            @on-ok="confirmCourse"
        >
            <courseList ref="courseList"></courseList>
        </Modal>

        <!--客户资料-->
        <Drawer
            v-if="archive.id && archive.id !== 0"
            v-model="archiveModal"
            title="客户资料"
            width="1000"
            placement="left"
            :mask-closable="true"
            :closable="true"
        >
            <ArchiveDetail v-if="archiveModal" :theCustomer="archive" :param="param"></ArchiveDetail>
        </Drawer>
    </div>
</template>

<script>
import {customerEdit} from '@api/customer';
import ArchiveDetail from '@/components/customer/ArchiveDetail';
// import ArchiveDetail from '../common/ArchiveDetail';
import courseList from '../common/courseList';
import {customerAdd, customerArchive, customerArchiveDetail, customerParam} from '../../../api/customer';
// import follow from "../common/follow";
import follow from '@/pages/customer/follow/index'
import CustomerStatus from '../../../components/field/customer/CustomerStatus';

export default {
    name: 'add',
    watch: {
        formData: function (val) {
            this.form = val;
        }
    },
    components: {
        follow, ArchiveDetail, courseList, CustomerStatus
    },
    data() {
        return {
            archiveModal: false,
            createModal: false,
            createCreating: true,
            Coursecolumns: [
                {
                    title: '课程名称',
                    key: 'name',
                    minWidth: 250,
                    show: true,
                    tooltip: true,
                },
                {
                    title: '课程模式',
                    key: 'method',
                    minWidth: 100,
                    show: true,
                    slot: 'method',
                },
                {
                    title: '机构分校',
                    key: 'org_school',
                    minWidth: 140,
                    slot: 'org_school',
                    show: true
                },
                {
                    title: '售价/划线价',
                    key: 'price',
                    minWidth: 100,
                    align: 'center',
                    slot: 'price',
                    show: true
                }
            ],
            columns: [
                {
                    title: '咨询项目',
                    key: 'title',
                    slot: 'title',
                    minWidth: 250,
                    show: true
                },
                {
                    title: '姓名',
                    key: 'name',
                    minWidth: 140,
                    slot: 'name',
                    show: true
                },
                {
                    title: '手机号',
                    key: 'phone',
                    minWidth: 130,
                    show: true
                },
                {
                    title: '微信号',
                    key: 'wechat',
                    minWidth: 130,
                    show: true
                },
                {
                    title: '状态',
                    key: 'status',
                    slot: 'status',
                    align: 'center',
                    minWidth: 100,
                    show: true,
                },
                {
                    title: '来源',
                    key: 'channel',
                    minWidth: 100,
                    slot: 'channel',
                    show: true
                },
                {
                    title: '意向度',
                    key: 'yxd',
                    minWidth: 100,
                    slot: 'yxd',
                    show: true
                },
                {
                    title: '行业',
                    key: 'hangye',
                    minWidth: 100,
                    slot: 'hangye',
                    show: true
                },
                {
                    title: '创建时间',
                    key: 'created_at',
                    minWidth: 170,
                    show: true
                },
                {
                    title: '操作',
                    slot: 'action',
                    align: 'center',
                    fixed: 'right',
                    minWidth: 120,
                    show: true
                }
            ],
            loading: false,
            current: 1,
            limit: 10,
            total: 0,
            param: {},
            courseParam: {}, //课程参数
            customer: {}, //当前操作线索

            creating: true,
            hasCourseModal: false, //已经存在课程
            hasCourseList: [], //已经存在的课程列表
            archive: {}, //档案信息
            grid: {
                xl: 12,
                lg: 12,
                md: 12,
                sm: 24,
                xs: 24
            },
            index: 1,
            keys: {},// 提取formFiled的字段
            form: {
                id: 0,
                name_type: '1',
                level_id: '',
                tj_phone: '',
                channel_id: '',
                yxd_id: '',
                content: '',
                pro_type: 2, // 项目类型
            },
            formRules: {
                channel_id: [
                    {required: true, message: '必选', trigger: 'change'}
                ],
                level_id: [
                    {required: true, message: '必选', trigger: 'change'}
                ],
                yxd_id: [
                    {required: true, message: '必选', trigger: 'change'}
                ],
                pro_type: [
                    {required: true, message: '必选', trigger: 'change'}
                ]
            },
            isOk: false, //是否允许提交表单
            courseModal: false, //课程弹窗

            archive_id: 0, //档案表
            selectCourseData: [],
            list: [], // 线索列表

            followDrawer: false,

        }
    },
    created() {
        this.archive_id = this.$route.query.archive_id;
        this.getArchive();
        this.getCustomer();
    },
    methods: {
        // 报名
        apply(row, index) {
            this.followDrawer = false;
            this.index = index;
            this.customer = row;
            this.$router.push({
                path: '/student/apply',
                query: {
                    id: row.id,
                    archive_id: row.archive_id
                }
            })
        },
        create() {
            this.form = {
                name_type: '1',
                pro_type: 2, // 项目类型
            };
            this.createModal = true;
        },
        confirmCreate() {
            this.$refs.create.validate(validate => {
                if (this.form.title == '' && this.form.course == '') {
                    return this.$Message.warning('请输入咨询内容');
                }
                if (validate) {
                    this.form.archive_id = this.archive.id;
                    customerAdd(this.form).then(res => {
                        if (res.code === 200) {
                            this.getCustomer();
                            this.createModal = false;
                            this.$Message.success(res.msg);
                        } else {
                            this.$Message.error(res.msg);
                        }
                        this.createCreating = false;
                        this.$nextTick(function () {
                            this.createCreating = true;
                        })
                    });
                } else {
                    this.createCreating = false;
                    this.$nextTick(function () {
                        this.createCreating = true;
                    })
                }
            });
        },
        courseAdd() {
            this.courseModal = true;
            // 获取课程信息
            this.$refs.courseList.getParam();
            this.$refs.courseList.getOrgList();
            this.$refs.courseList.getData();
        },
        // 获取参数信息
        getParam() {
            customerParam().then(res => {
                this.param = res.data;
            });
        },
        // 确定课程
        confirmCourse() {
            this.courseParam = this.$refs.courseList.param;
            let courseList = this.$refs.courseList.selectedData;
            this.selectCourseData = courseList;
            if (courseList == null || courseList == '') {
                return this.$Message.error('请选择课程');
            }
            // 检查课程是否已经存在
            let course = []; //课程列表
            let course_ids = []; // 课程id
            courseList.forEach(item => {
                course_ids.push(item.id);
                let data = {};
                data.id = item.id;
                data.name = item.name;
                data.school_id = item.school_id;
                course.push(data);
            })
            this.isOk = true;
            this.form.course = course;
        },
        removeCourse(index) {
            this.form.course.splice(index, 1);
            this.selectCourseData.splice(index, 1);
        },
        // 提交数据
        submitForm() {
            this.$refs.create.validate((valid) => {
                if (valid) {
                    customerEdit(this.form).then(res => {
                        this.submitResult(res);
                    });
                }
            })
        },
        // 表单提交结果
        submitResult(result) {
            this.$emit('submitResult', result);
        },
        // 获取档案信息
        getArchive() {
            customerArchiveDetail({archive_id: this.archive_id}).then(res => {
                this.archive = res.data;
            });
        },
        // 获取线索
        getCustomer() {
            customerArchive({archive_id: this.archive_id}).then(res => {
                let {data, total} = res;
                this.list = data;
                this.total = total;
            });
        },

        // 跟进
        follow(index) {
            this.index = index;
            this.customer = this.list[index];
            this.followDrawer = true;
        },
        // 标记无效,1、转入公海无效,2、删除当前数据
        setTypeResult() {
            this.followDrawer = false;
            this.list.splice(this.index, 1);
        },

        // 选中一项,将数据添加至已选项中
        handleSelect(selection, row) {
            this.selectedData.push(row);
        },
        // 取消选中一项,将取消的数据从已选项中删除
        handleSelectCancel(selection, row) {
            const index = this.selectedData.findIndex(item => item.name === row.name);
            this.selectedData.splice(index, 1);
        },
        // 当前页全选时,判断已选数据是否存在,不存在则添加
        handleSelectAll(selection) {
            selection.forEach(item => {
                if (this.selectedData.findIndex(i => i.name === item.name) < 0) {
                    this.selectedData.push(item);
                }
            });
        },
        // 取消当前页全选时,将当前页的数据(即 dataWithPage)从已选项中删除
        handleSelectAllCancel() {
            this.selectedData = [];
        },
        // 切换每页条数
        handleChangePageSize(limit) {
            this.limit = limit;
            this.getData();
        }
    },
    mounted() {
        this.getParam();
    },
    computed: {
        labelWidth() {
            return this.isMobile ? undefined : 100;
        },
        labelPosition() {
            return this.isMobile ? 'top' : 'right';
        },
        labelKeys: function () {
            let ids = [];
            this.selectLabelData.forEach(item => {
                ids.push(item.id);
            })
            return ids;
        },
        // 动态设置列
        tableColumns() {
            const columns = [...this.columns];
            return columns.filter(item => item.show);
        }
    }
}
</script>
<style scoped>

</style>


组件传值

父组件

<template>
  <div>
    <child :list="list" ref="child"></child>
  </div>
</template>
<script>
  import child from '@/components/child';
  export default {
      data(){
        return {
         	list: []   
        }  
      },
    components: {
      child
    },
    methods: {
      fatherMethod() {
        console.log('father组件');
      },
        // 调用子组件的方法
        handChildMethods(){
            this.$refs.child.childMethods()
        }
    }
  }
</script>

子组件

<template>
  <div @click="activeBtn"> </div>
</template>
<script>
  export default {
    // 接受父组件的值,使用:this.list
      props:{
          list:{
              type: Array,
              default: []
          }
      },
    methods: {
      activeBtn() {
          // 调用父组件的方法
        this.$parent.fatherMethod()
          this.$emit('fatherMethod')
      },
        // 子组件自己的方法
        childMethods(){
            console.log("子组件自己的方法");
        }
    }
  }
</script>

表单

 <Form ref="form" :model="form" :rules="formRule" :label-width="80">
     <Row>
         <Col span="12">
             <FormItem label="微信号" prop="name">
                 <Input v-model="form.name" placeholder=""></Input>
             </FormItem>
         </Col>
         <Col span="24">
             <FormItem>
                 <Button type="primary" @click="submitForm('form')">保 存</Button>
                 <Button @click="resetForm('form')" style="margin-left: 8px">重 置</Button>
             </FormItem>
         </Col>
     </Row>
</Form>
// data
keys:{},
form: {
  id: "",
  name: "",
},
formRule: {
  name: [
    {required: true, message: '网站名称不能为空', trigger: 'blur'}
  ],
}

created() {
    // 表单提交值
    this.keys = Object.keys(this.form);
},

// methods
submitForm(name) {
  this.$refs[name].validate((valid) => {
    if (valid) {
      websiteStore(_.pick(this.form,this.keys)).then(res=>{
        this.$Message.success('Success!');
      });
    }
  })
},
resetForm(name) {
  this.$refs[name].resetFields();
}

表单验证规则

string
number
boolean
method
regexp
integer
float
array
object
enum
date
url
hex
email
any




:rules="formRules"

formRules: {
        name: [
            {required: true, message: '请输入机构名称', trigger: 'blur'}
        ],
        phone: [
            {required: true, message: '请输入电话号码', trigger: 'blur'},
            {min:11, message: '手机号码必须为11位', trigger: 'blur'},
            {max:11, message: '手机号码必须为11位', trigger: 'blur'},
        ],
         email: [
             { type:"email", message: '请输入正确的邮箱格式', trigger: 'blur'}
         ]
            },
const descriptor = {
  role: { type: 'enum', enum: ['admin', 'user', 'guest'] },
};

下拉框验证

{ type: 'number', required: true, message: '请选择案件类型', trigger: 'change' }

必须是字符串验证

表单提交

ui-form-submit

formSubmit() {
    this.$refs.create.validate((valid) => {
        if (valid) {
            $method$(_.pick(this.form, this.keys)).then(res => {
                if (res.code === 200) {
                    this.$Message.success(res.msg);
                    this.showCreate = false;
                    this.creating = false;
                    this.$nextTick(() => {
                        this.creating = true;
                    });
                    if (this.form.id > 0) {
                        const index = this.list.findIndex(item => item.id === this.form.id);
                        this.list[index] = this.form;
                    } else {
                        this.getData();
                    }
                } else {
                    this.$Message.error(res.msg);
                    this.showCreate = true;
                    this.creating = false;
                    this.$nextTick(() => {
                        this.creating = true;
                    });
                }
            });
        } else {
            this.creating = false;
            this.$nextTick(() => {
                this.creating = true;
            });
        }
    });
},

单选

ui-radio

<RadioGroup v-model="">
    <Radio 
           v-for="(item,index) in $list$" 
           :key="index" :label="item.id"
           :true-value="true"
           :false-value="false"
           >{{ item.name }}</Radio>
</RadioGroup>

下拉

ui-select

 <Select clearable v-model="form.$value$" >
        <Option 
                v-for="(item,index) in list" 
                :key="index" 
                :value="item.id" 
                >{{ item.name }}</Option>
</Select>

开关

ui-switch

<Switch size="$size$" v-model="value" :true-value="$true_value$" :false-value="$false_value$" :loading="true" @on-change="changeStatus">
    <span slot="open">开启</span>
    <span slot="close">关闭</span>
</Switch>

enum("default","large","small")
enum("true","1")
enum("false","0","2")

表格

层级处理::transfer=“true”

<template slot-scope="{ row, index }" slot="action">
    <Button type="primary" size="small" style="margin-right: 5px" @click="edit(index)">编辑</Button>
    <Button type="error" size="small" @click="delete(index)">删除</Button>
</template>
  <Dropdown @on-click="(name) => action(name, index)" :transfer="true">
                        <a type="text">更多
                            <Icon type="ios-arrow-down"/>
                        </a>
                        <DropdownMenu slot="list" trigger="hover" :transfer="true">
                            <DropdownItem name="detail">线索详情</DropdownItem>
                            <DropdownItem name="editArchive">编辑客户</DropdownItem>
                            <DropdownItem name="transfer">转移线索</DropdownItem>
                            <DropdownItem name="project">新增项目</DropdownItem>
                            <DropdownItem divided name="delete">删除</DropdownItem>
                        </DropdownMenu>
                    </Dropdown>

 <template slot-scope="{ row }" slot="name">
     <strong>{{ row.name }}</strong>
</template>

 // 更多
action(name, index) {
    this.setCustomerByIndex(index);
    switch (name) {
        case 'editArchive':
            this.archiveEditModal = true;
            break;
        case 'detail':
            // this.detailShow = true;
            this.edit(index, true)
            break;
        case 'delete':
            this.$Modal.confirm({
                title: '删除提示',
                content: `是否删除${this.list[index].title}`,
                onOk: () => {
                    customerDelete({id: this.list[index].id}).then(res => {
                        this.list.splice(index, 1);
                        this.$Message.success(res.msg);
                    });
                }
            });
            break;
        case 'transfer': // 转移线索
            this.transferModal = true;
            break;
        case 'project':
            this.$router.push({
                path: '/customer/add',
                query: {
                    archive_id: this.customer.archive_id
                }
            });
            break;
    }
},

表格查询参数

ui-table-form
<template>
    <Form ref="form" :model="data" :rules="rules" :label-width="labelWidth" :label-position="labelPosition">
        <Row :gutter="24" type="flex" justify="space-between">
            <Col v-bind="grid">
                <FormItem label="名字:" prop="name" label-for="name">
                    <Input v-model="data.name" placeholder="请输入" element-id="name"/>
                </FormItem>
            </Col>
            <Col v-bind="grid">
                <FormItem label="创建时间:" prop="datebt" label-for="datebt">
                    <DatePicker type="daterange" v-model="data.datebt" format="yyyy-MM-dd HH:mm:ss"
                                placeholder="请选择时间"></DatePicker>
                </FormItem>
            </Col>
            <template v-if="collapse">

            </Col>
            </template>
            <Col v-bind="grid" class="ivu-text-right">
                <FormItem>
                    <Button type="primary" @click="handleSubmit">查询</Button>
                    <Button class="ivu-ml-8" @click="handleReset">重置</Button>
                    <a v-font="14" class="ivu-ml-8" @click="collapse = !collapse">
                        <template v-if="!collapse">
                            展开
                            <Icon type="ios-arrow-down"/>
                        </template>
                        <template v-else>
                            收起
                            <Icon type="ios-arrow-up"/>
                        </template>
                    </a>
                </FormItem>
            </Col>
        </Row>
    </Form>
</template>
<script>
import {mapState} from 'vuex';

export default {
    props: {},
    data() {
        return {
            grid: {
                xl: 6,
                lg: 6,
                md: 6,
                sm: 24,
                xs: 24
            },
            collapse: false,
            data: {
                name: '',
                databt: [],
            },
            rules: {}
        }
    },
    computed: {
        ...mapState('admin/layout', [
            'isMobile'
        ]),
        labelWidth() {
            return this.isMobile ? undefined : 100;
        },
        labelPosition() {
            return this.isMobile ? 'top' : 'right';
        }
    },
    methods: {
        handleSubmit() {
            this.$emit('on-submit', this.data);
        },
        handleReset() {
            this.$refs.form.resetFields();
            this.$emit('on-reset');
        }
    }
}
</script>

表格辅助方法

// 改变表格尺寸
handleChangeTableSize(size) {
    this.tableSize = size;
},
// 表格全屏
handleFullscreen() {
    this.tableFullscreen = !this.tableFullscreen;
    this.$emit('on-fullscreen', this.tableFullscreen);
},
// 刷新表格数据
handleRefresh() {
    this.getData();
},
// 重置表格列设置
handleResetColumn() {
    this.columns = this.columns.map(item => {
        const newItem = item;
        newItem.show = true;
        return newItem;
    });
},

表格内文字内容过长时

.text-two-line
<Ellipsis :text="row.intro" :height="100" tooltip />
<h3>属性</h3>
<h5>text</h5> 							//文本
<h5>height</h5>							//限制高度(指定文字大小)
<h5>lines</h5>							//指定行数,与height连用时会被忽略
<h5>length</h5>							//指定长度
<h5>full-width-recognition</h5>			//是否将全角字符的长度视为2来计算字符串长度,适用于 length	
<h5>disabled</h5>						//是否禁用	
<h5>tooltip	</h5>						//是否开启 tooltip	
<h5>transfer</h5>						//tooltip 的 transfer 属性	
<h5>theme</h5>							//tooltip 的 theme 属性,可选值为 light 或 dark	
<h5>max-width</h5>						//tooltip 的 max-width 属性	
<h5>placement</h5>						//tooltip 的 placement 属性	


<h3>事件</h3>
<h5>on-show</h5>						//文本全部展示的时候触发
<h5>on-hide</h5>						//文本省略的时候触发																					

公共方法

return {
    grid: {
        xl: 24,
        lg: 24,
        md: 24,
        sm: 24,
        xs: 24
    },
    list: [], // 数据列表
    loading: false,
    submitting: true, // 表单提交状态
    form: {
        name: '',
        url: "",
    },
    formRule: {
        name: [
            {required: true, message: '名称不能为空', trigger: 'blur'}
        ],
        url: [
            {required: true, message: '地址不能为空', trigger: 'blur'},
            {type: "url", message: '地址格式不正确', trigger: 'blur'}
        ],
    },
}
mounted () {
    this.getData();
},
    created() {
        // 表单提交值
        this.keys = Object.keys(this.form);
    },
// 重载表格
reloadTable() {
    this.list = [];
    this.getData();
},
    copyData(index) {
        return cloneDeep(this.list[index]);
    },
        // 切换页面
        changePage(page){
            this.page = page;
            this.getData();
        }
    

分页

 <div class="ivu-mt ivu-text-right">
     <Page :total="total" show-sizer show-elevator
           :page-size="limit" show-total
           :page-size-opts="[15,30,50,100]"
           :simple="isMobile"
           @on-change="changePage"
           @on-page-size-change="changeLimit"
           @on-prev="prevPage"
           @on-next="nectPage"
           />
</div>
// 切换页码
changePage(page){
    this.page = page;
    this.getData();
},
// 切换条数
changeLimit(limit){
    this.limit=limit;
},
// 上一页
prevPage(page){
    this.page = page;
    this.getData();
},

// 下一页
nectPage(page){
    this.page = page;
    this.getData();
}

table选择

@on-sort-change="handleSortChange"
@on-filter-change="handleFilterChange"
@on-select="handleSelect"
@on-select-cancel="handleSelectCancel"
@on-select-all="handleSelectAll"
@on-selection-change="selectChange"

清空

// 清空所有已选项this.selectedData = [];
handleClearSelect() {
    let ids = [];
    this.selectedData.forEach(item=>{
        ids.push(item.id);
    })
    this.$Modal.confirm({
        title: '删除提示',
        content: `是否删除?`,
        onOk: () => {
            deleteCate({ids}).then(res => {
                this.$Message.success(res.msg);
                this.selectedData = [];
                this.getData();
            });
        }
    });
},
 // 点击排序按钮时触发
        handleSortChange({key, order}) {
            // 将排序保存到数据
            this.sortColumns = key;
            this.sortType = order;
            this.current = 1;
        },
        // 过滤条件改变时触发
        handleFilterChange() {
            // 从第一页开始
            this.current = 1;
        },
        // 选中一项,将数据添加至已选项中
        handleSelect(selection, row) {
            this.selectedData.push(row);
        },
        // 取消选中一项,将取消的数据从已选项中删除
        handleSelectCancel(selection, row) {
            const index = this.selectedData.findIndex(item => item.name === row.name);
            this.selectedData.splice(index, 1);
        },
        // 当前页全选时,判断已选数据是否存在,不存在则添加
        handleSelectAll(selection) {
            selection.forEach(item => {
                if (this.selectedData.findIndex(i => i.name === item.name) < 0) {
                    this.selectedData.push(item);
                }
            });
        },
        // 选项发生改变时
        selectChange(selection){
            this.selectedData = selection;
        },

时间处理

<Col v-bind="grid">
    <Col v-bind="grid">
        <FormItem label="到期时间" prop="etime">
            <DatePicker
                        v-model="form.etime"
                        type="date"
                        format="yyyy-MM-dd HH:mm:ss"
                        @on-change="changeTime"
                        placeholder="请选择时间" style="width: 200px"></DatePicker>
        </FormItem>
    </Col>
</Col>
etime:'2021-11-26 00:00:00',

// 选择时间
changeTime(selectedDate){
    this.form.etime = selectedDate;
},

// this.form.expire_time 时间对象
this.$Date(this.form.expire_time).format('YYYY-MM-DD HH:mm:ss');

图片放大

// 图片放大
import "viewerjs/dist/viewer.css"
import VueViewer from 'v-viewer'
Vue.use(VueViewer);

// 查看大图
bigPic(image) {
    this.$viewerApi({images:[image]})
},
// 图片放大
bigPic(url) {
    let list = [];
    list.push(url);
    this.$viewerApi({
        images: list, // 必须是已数组的形式传递 ["image.png","avatar.png",....]
    })
},

单选

ui-radio
<RadioGroup v-model="menuData.node_type" @on-change="changeNodeType">
     <Radio label="1">永久有效</Radio>
     <Radio label="2">到期时间</Radio>
</RadioGroup>

布局

<Modal
    v-model="modal"
    :title="title"
       :loading="creating"
       :fullscreen="true"
       :transfer="false"
       @on-ok="confirm"
       @on-cancel="cancel">
    
</Modal>

ui-modal
enum("false","true")
<Row type="flex" align=$alias$ justify="$justify$" gutter="$gutter$" wrap="$wrap$">
    
</Row>

ui-row
enum("top","middle","bottom")
enum("start","end","center","space-around","space-between" )
enum(0,8,24)
enum("true","false")
enum("",span","offset","push","pull")
 <Col v-bind="grid" $tips$>
   
</Col>

常规状态

<Tag v-if="row.sex === 0">未知</Tag>
<Tag v-if="row.sex === 1" color="blue"></Tag>
<Tag v-if="row.sex === 2" color="magenta"></Tag>

表格菜单下拉

ui-tb-action-more

<template slot-scope="{ row, index }" slot="action">
    <a @click="handleUpdate(index)">跟进</a>
    <Divider type="vertical" />
    <Dropdown @on-click="(name) => action(name, index)">
        <a type="text">更多<Icon type="ios-arrow-down" /></a>
        <DropdownMenu slot="list" trigger="hover" transfer="true" >
            <DropdownItem name="edit">编辑</DropdownItem>
            <DropdownItem name="detail">详情</DropdownItem>
            <DropdownItem divided name="delete">删除</DropdownItem>
        </DropdownMenu>
    </Dropdown>
</template>
// 更多
action(name) {
    switch (name) {
        case "edit":

            break;
        case "detail":

            break;
        case "delete":

            break;
    }
},

时间轴

ui-timeline

<Timeline>
    <TimelineItem color="$poprs$">
        <p class="time">1976年</p>
        <p class="content">Apple I 问世</p>
    </TimelineItem>
    <TimelineItem>
        <p class="time">1984年</p>
        <p class="content">发布 Macintosh</p>
    </TimelineItem>
    <TimelineItem>
        <p class="time">2007年</p>
        <p class="content">发布 iPhone</p>
    </TimelineItem>
    <TimelineItem>
        <p class="time">2010年</p>
        <p class="content">发布 iPad</p>
    </TimelineItem>
    <TimelineItem>
        <p class="time">2011年10月5日</p>
        <p class="content">史蒂夫·乔布斯去世</p>
    </TimelineItem>
</Timeline>


enum("green",'red','blue')

图标

ui-icon

<Icon type="$type$" $props$ />


enum("md-add",'md-clipboard')
enum("size",'color','custom')

Driawer

<Drawer
        :title="detail.name"
        v-model="showDrawer"
        width="720"
        placement="right"
        :mask-closable="true"
        :closable="true"
        >

    <div class="drawer-footer">
        <Button style="margin-right: 8px" @click="value3 = false">关闭</Button>
        <Button type="primary" @click="value3 = false">Submit</Button>
    </div>
</Drawer>
showDrawer:true,
    
    
.drawer {
    &-footer {
        width: 100%;
        position: absolute;
        bottom: 0;
        left: 0;
        border-top: 1px solid #e8e8e8;
        padding: 10px 16px;
        text-align: right;
        background: #fff;
    }
}

弹窗表单

<Form :model="form" :rules="formRules" :label-width="labelWidth" :label-position="labelPosition" ref="create">
            <Row :gutter="24" justify="start">
                <Col space="8">
                    <Col v-bind="grid">
                        <FormItem label="姓名:" prop="title" label-for="name">
                            <Input v-model="form.name" placeholder="" @on-blur="checkUser"/>
                        </FormItem>
                    </Col>
                    <Col v-bind="grid">
                        <FormItem label="咨询人类型" prop="name_type">
                            <Select v-model="form.name_type" placeholder="请选择">
                                <Option value="1" selected>本人</Option>
                                <Option value="2">代咨询</Option>
                            </Select>
                        </FormItem>
                    </Col>
                    <Col v-bind="grid">
                        <FormItem label="性别" prop="sex">
                            <RadioGroup v-model="form.sex">
                                <Radio label="1"></Radio>
                                <Radio label="2"></Radio>
                            </RadioGroup>
                        </FormItem>
                    </Col>
                    
                <Col span="24">
                    <FormItem label="咨询内容" prop="content">
                        <Input v-model="form.content" type="textarea" :autosize="{minRows: 4,maxRows: 8}"
                               placeholder="请输入咨询内容"></Input>
                    </FormItem>
                </Col>
            </Row>
        </Form>
 computed: {
        labelWidth() {
            return this.isMobile ? undefined : 100;
        },
        labelPosition() {
            return this.isMobile ? 'top' : 'right';
        },
    }

性别

 <Tooltip content="">
     <Icon type="md-male" color="primary"/>
</Tooltip>
<Tooltip content="">
    <Icon type="md-female" color="red"/>
</Tooltip>

地址

<Col span="24">
    <FormItem label="地址" prop="addr">
        <i-region v-model="form.addr"/>
    </FormItem>
</Col>
<Col span="24">
    <FormItem label="详细地址" prop="addr_detail">
        <Input v-model="form.addr_detail" type="textarea" :autosize="{minRows: 3,maxRows: 6}"
               placeholder="请输入详细地址"></Input>
    </FormItem>
</Col>

格式化地址

<template slot-scope="{ row }" slot="addr">
    {{ transformAddr(row.addr)}}
    <p> &nbsp;&nbsp;{{ row.addr_detail }}</p>
</template>
transformAddr(addr=[]){
    if (addr == null || addr == '' || addr.length == 0){
        return  "";
    }
    let str = "";
    if (addr.length > 0){
        addr.forEach(item=>{
            str += " " +item.name;
        })
    }
    return str;
},

时间查询

ui-date-search

<FormItem label="创建时间:" prop="date" label-for="btdate">
     <DatePicker v-model="data.btdate" type="daterange" :options="dateOptions" placeholder="请选择时间" />
</FormItem>

ui-date-search-dateOptions

date: []

dateOptions: {
    shortcuts: [
        {
            text: '今天',
            value: () => {
                const date = this.$Date(new Date()).format('YYYY-MM-DD');
                return [date, date];
            }
        },
        {
            text: '昨天',
            value: () => {
                let date = new Date();
                date.setTime(date.getTime() - 3600 * 1000 * 24);
                date = this.$Date(date).format('YYYY-MM-DD');
                return [date, date];
            }
        },
        {
            text: '本周',
            value: () => {
                const date = new Date();
                const start = this.$Date(date).day(1).format('YYYY-MM-DD');
                const end = this.$Date(date).day(7).format('YYYY-MM-DD');
                return [start, end];
            }
        },
        {
            text: '本月',
            value: () => {
                const date = new Date();
                const start = this.$Date(date).date(1).format('YYYY-MM-DD');
                const end = this.$Date(date).add(1, 'month').date(1).subtract(1, 'day').format('YYYY-MM-DD');
                return [start, end];
            }
        }
    ]
}

支付状态

ui-badge

<Badge color="$COLOR$" text="$TEXT$" />

enum("blue","green","red")
enum("支付成功","支付失败","正常","关闭","失败")

提示

ui-tooltip

<Tooltip max-width="200" content="$content$">
    {{ $content$ }}
</Tooltip>

消息提示

this.$Message.success(res.msg);
this.$Message.error(res.msg);
this.$Message.warning(res.msg);

enum('success','error','warning')
enum('res.msg','666'')

时间格式化方法

ui-date-format

 formatDate(timestamp) {
     return this.$Date.unix(timestamp).format('$type$');
 },
enum('YYYY-MM-DD  HH:mm:ss','YYYY-MM-DD','HH:mm:ss')

单删除

ui-del-one

批量删除

ui-del-batch

clearSelect() {
    let ids = [];
    this.selectedData.forEach(item => {
        ids.push(item.id);
    })
    this.$Modal.confirm({
        title: '删除提示',
        content: `是否删除已选择项?`,
        onOk: () => {
            $method$({ids}).then(res => {
                this.$Message.success(res.msg);
                this.selectedData = [];
                this.getData();
            });
        }
    });
},

消息提示

io-notice

this.$Notice.$type$({
    title: '温馨提示',
    desc: res.msg,
    duration: 5
});

enum("open","success","error","warning","info")

头像渲染

ui-avatar

<span @click="bigPic($name$)">
     <Avatar icon="ios-person" :src="$name$" size="$size$" shape="$shape$"/>
</span>

enum("default","large","small","64")
enum("circle","square")
enum("pic","avatar","img","url","form.pic","form.avatar","form.img","form.url")

性别

ui-sex

<div class="ivu-ml">
        {{ row.name }}
        <Tooltip content="" v-if="row.sex == 1">
            <Icon :type="md-male" color="primary"/>
        </Tooltip>
        <Tooltip content="" v-if="row.sex == 2">
            <Icon type="md-female" color="red"/>
        </Tooltip>
    </div>

返回方法

this.$refs.form.validate((valid) => {
                if (valid) {
                    agentStore(_.pick(this.form, this.keys)).then(res => {
                        res.code === 200 ? this.$Message.success(res.msg) : this.$Message.error(res.msg);
                        this.submitting = true;
                        this.agentModal = false;
                        this.getData();
                        this.$nextTick(() => {
                            this.submitting = true;
                        });
                    });
                } else {
                    this.submitting = false;
                    this.$nextTick(() => {
                        this.submitting = true;
                    });
                }
            });

ui-msg

this.$Message.$TYPE$(res.msg);
enum("success","error","warning","info","loading");

Poptip

ui-poptip

<Poptip
    :transfer="true"
    trigger="$trigger$"
    placement="$placement$"
    :title="标题"
>
    <span>提示</span>
    <template slot="content" >
        <div>
            
        </div>
    </template>
</Poptip>

enum("hover","click","focus")
enum("toptop-start","top-end","bottom","bottom-start","bottom-end","left","left-start","left-end","right","right-start","right-end")

表格过滤

@on-filter-change="filterChange"
 // 过滤条件改变时触发
handleFilterChange () {
    // 从第一页开始
    this.current = 1;
},
 ui-table-filter

filters: [
    {
        label: '关闭',
        value: 0
    },
    {
        label: '运行中',
        value: 1
    },
    {
        label: '已上线',
        value: 2
    },
    {
        label: '异常',
        value: 3
    }
],
    filterMultiple: true, // 是否支持多选
    filterRemote (value) {
        // 切换过滤条件时,将条件保存到本地
        this.filterType = value;
}

数值显示

<CountUp :end="$number$" :duration="$duration$" ref="count" v-font="$font$" />

enum("form.number","number","count","total")
enum("3","4","5","6")
enum("24","25","26","27","28","29","30")

对象复制

this.$key$ = Object.keys(this.$name$);

enum("keys")
enum("form")

方法

iview中vuex使用方式

设置

import {getWebsiteInfo} from "@api/system";
import {Message} from "view-design";
import util from '@/libs/util';

export default {
	namespaced: true,
	state: {
		website: {},
	},
	actions: {
		getWebsite({state, commit, dispatch}) {
			getWebsiteInfo().then(async res => {
				Message.destroy();
				let {data} = res;
				dispatch('set', data);
				util.storage.set("website", res.data);
			});
		},

		/**
		 * @description 持久化保存网站信息
		 * @param {Object} state vuex state
		 * @param {Object} dispatch vuex dispatch
		 * @param {*} info info
		 */
		set({state, dispatch}, data) {
			return new Promise(async resolve => {
				// store 赋值
				state.website = data;
				// 持久化
				await dispatch('admin/db/set', {
					dbName: 'sys',
					path: 'system.website',
					value: data,
				}, {root: false});
				// end
				resolve();
			})
		},
		/**
		 * @description 获取网站信息
		 * @param {Object} state vuex state
		 * @param {Object} dispatch vuex dispatch
		 */
		load({state, dispatch}) {
			return new Promise(async resolve => {
				// store 赋值
				state.info = await dispatch('admin/db/get', {
					dbName: 'sys',
					path: 'system.website',
					defaultValue: {},
				}, {root: true});
				// end
				resolve();
			})
		}
	},
	mutations: {
		// 从本地缓存中加载 网站配置
		setWebsite(state) {
			state.website = util.storage.get("website");
		}
	}
}

获取

 computed: {
      ...mapState("admin/system", [
            "website"
        ])
 }

解决刷新后失效?

需要在main.js文件中动态加载

created() {
    // 获取网站信息
		let website = util.storage.get("website");
		if (website == null || website == undefined || website == '') {
			this.$store.dispatch("admin/system/getWebsite");
		} else {
			this.$store.commit('admin/system/setWebsite');
		}
}

删除

// 清空所有已选项
handleClearSelect() {
    let ids = [];
    this.selectedData.forEach(item=>{
        ids.push(item.id);
    })
    this.$Modal.confirm({
        title: "删除提醒!",
        content: "是否确定删除?",
        onOk: () => {
            articleCateDelete({ids}).then(res=>{
                this.getData();
                this.$Message.success(res.msg);
            });
        }
    });
    this.selectedData = [];
},

遍历二维数组的children添加到Arrary里

 getCateList(){
     courseCateList().then(res => {
         this.cateList = res.data;
         this.cateList.forEach(item=>{
             if (item.children.length > 0){
                 item.children.forEach(childItem=>{
                     this.cateList.push(childItem)
                 })
             }
         });
     });
 },

通过id查找列表的当前item

//根据字段找 item 
getItemById(id) {
     return this.list.find(item => item.id === id);
 },
    
let list = [
    {id:1,name"orangbus"},
    {id:1,name"orangbus"},
    {id:1,name"orangbus"},
    {id:1,name"orangbus"},
    {id:1,name"orangbus"},
];

ithis.list[index]

对象复制

import {cloneDeep} from 'lodash';

this.form = cloneDeep(item);

树结构编辑

通过id


递归找子集

 ChilderTree(val) {
    //声明一个数组准备接收匹配好的数据
    let arr = [];
    //判断传过来的数组长度
    if (val.length !== 0) {
        //遍历匹配,把满足条件的数据追加到arr数组中,最后返回一个结果
        val.forEach((item) = >{
            let obj = {};
            obj.deptId = item.deptId;
            obj.label = item.deptName;
            obj.value = item.deptId;
            obj.disabled = item.status == 0 ? true: false;;
            if (item.children.length >= 1) {
                obj.children = this.ChilderTree(item.children);
            }
            arr.push(obj);
        });
    }
    return arr;
},

数组搜索

sortLists() {
			let That = this;
			if (!That.keywords) {
				return That.lists;
			} else {
				return this.lists.filter(function(item) {
					return item.name.includes(That.keywords);
				});
			}
		}

更改当前tab标签

this.$store.dispatch('admin/page/currentUpdate', {
    meta: {
        title: '新的标题'
    }
});

获取vuex信息

async function getUserAccess() {
	return await store.dispatch('admin/db/get', {
		dbName: 'sys',
		path: 'user.info',
		defaultValue: '',
		user: true // 是否区分用户
	});
}

getUserAccess().then(res => {
    access = res.access;
    let md5_data = md5(access.toString());
    config.headers.common['crm'] = md5_data;
})

刷新用户信息

import {mapActions} from 'vuex';

 methods: {
     ...mapActions('admin/user', [
            'refreshUserInfo'
        ]),
 }
    
this.refreshUserInfo();

render 函数用法

{
    title: 'name',
        key: 'name',
            tree: true,
                render: (h, data) => {
                    let {row} = data;
                    let _this = this;
                    // 标签,属性对象,子元素
                    return h("span", {
                        class: "text-pointer",
                        // 点击事件
                        on: {
                            click: () => {
                                _this.$Copy({
                                    text: row.password
                                });
                            }
                        }
                    }, data.row.name)
                }
},

时间操作

获取当前时间戳

this.$Date().unix()

unix时间转换

this.$Date(1641180193*1000).format("YYYY-MM-DD HH:mm:ss")

获取当前年月

// 设置当前年月
this.param.year = this.$Date().format('YYYY') * 1;
this.param.month = this.$Date().format('M') * 1;

ui-date
this.$Date().format('$layout$');
enum("YYYY-MM-DD HH:mm:ss","YYYY-MM-DD","HH:mm:ss","YYYY","M")

日期转unix时间戳

this.$Date(2-04-22).unix()

树结构

$list = collect($data)->map(function ($item) {
    $item->expand = true;
    if (!empty($item->children)) {
        for ($i = 0; $i < $item->children->count(); $i++) {
            $temp = [];
            $temp['value'] = $item->children[$i]['id'];
            $temp['title'] = $item->children[$i]['name'];
            $temp['selected'] = false;
            $temp['checked'] = true;
            $tempItem['expand'] = true; //是否展开直子节点
            $item->school[$i] = $temp;
        }
    }
    $tempItem = [];
    $tempItem["title"] = $item['name'];
    $tempItem["value"] = $item['id'];
    $tempItem['selected'] = false;
    $tempItem['checked'] = true; //是否勾选(如果勾选,子节点也会全部勾选)
    $tempItem['disabled'] = true; // 顶级目录不可选择
    $tempItem['expand'] = true; //是否展开直子节点
    $tempItem['children'] = $item['children'];
    return $tempItem;
});

封装组件

(单 )图片/文件 上传

<FileUpload :url="form.pic" title="请选择图片" @upload="upload" @remove="removeUpload" />
// 导入组件
import FileUpload from "@/components/upload/FileUpload";

// 注册组件
 components:{
      FileUpload  
    },

// 方法接受文件上传结果
upload(res) {
    this.form.pic = res.data.url
},
// 删除文件,返回 true|false
removeUpload(result){
    if(result){
        this.form.pic = "";
    }
},
ui-upload-html // 图片上传

<FileUpload :url="form.pic" title="请选择图片" @upload="upload" @remove="removeUpload" />
ui-upload-js // 文件上传接受返回值

// 方法接受文件上传结果
upload(res) {
    this.form.pic = res.data.url
},
// 删除文件,返回 true|false
removeUpload(result){
    if(result){
        this.form.pic = "";
    }
},
ui-upload-components // 文件上传组件

components:{
    FileUpload  
},

头像上传

<AvatarUpload :url="form.pic" filed="pic" title="请选择图片" @upload="upload" @remove="removeUpload" />

ui-upload-avatar-html

enum("pic","url","avatar","poster")
// 导入组件
import FileUpload from "@/components/upload/AvatarUpload";

// 注册组件
 components:{
      AvatarUpload  
    },

// 方法接受文件上传结果
upload(res) {
    this.form.pic = res.data.url
},
// 删除文件,返回 true|false
removeUpload(result){
    if(result){
        this.form.pic = "";
    }
},
ui-upload-avatar // 图片上传

<FileUpload :url="form.pic" title="请选择图片" @upload="upload" @remove="removeUpload" />
ui-upload-js // 文件上传接受返回值

// 方法接受文件上传结果
upload(res) {
    this.form.pic = res.data.url
},
// 删除文件,返回 true|false
removeUpload(result){
    if(result){
        this.form.pic = "";
    }
},
ui-upload-components // 文件上传组件

components:{
    FileUpload  
},

多图上传

<FormItem label="图片" prop="images">
       <ImagesUpload :imagesList="form.images" @uploadImages="uploadImages"></ImagesUpload>
</FormItem>

images:[
	{name:'张三.jpg',url:'https://xxx.xom/张三.jpg'},
    {name:'张三.jpg',url:'https://xxx.xom/张三.jpg'},
    {name:'张三.jpg',url:'https://xxx.xom/张三.jpg'},
]
import ImagesUpload from "@/components/upload/ImagesUpload";


 components:{
       ImagesUpload
    },
   
 // 多图图片上传
uploadImages(imageList){
   this.form.images = imageList;
},
        

部门管理

<DepartMent :selected_ids="form.major_id" @getIds="getIds"></DepartMent>
import DepartMent from "@/components/common/department";

components: {
   DepartMent
},
        
getIds(uid){
   this.form.uid = uid;
},    

selected_ids: array | Number | String

组织人员

<RoleUserList :value="value" @getSelected="getSelected" ref="roleUserList"></RoleUserList>
import RoleUserList from "@/components/common/roleUserList"

components:{
    RoleUserList
},

    //获取已经选择的数据id
getSelected(item){
    console.log(item)
}

value: array | number

multiple: true | false

使用时需要触发获取数据

getData(){
	this.$refs.roleUserList.getData();
},

角色用户

<RoleUser @getSelected="getSelected" :value="1" :multiple="false"></RoleUser>
import RoleUser from "@/components/common/roleUserList"

components:{
     RoleUser
 },
        
getSelected(ids){
    console.log(ids)
}     

todo

组织校区

 <OrgSchool :selected_ids="form.school_id" @getSchoolId="getSchoolId" :multiple="false"  ref="orgSchool"></OrgSchool>
import OrgSchool from "@/components/common/OrgSchool";

components:{
   OrgSchool
},

this.$refs.orgSchool.getData();
    
getSchoolId(id){
    console.log(id)
}

textbus富文本编辑器 -废弃

<TextBus :content="form.content"  ref="edit"></TextBus>
// 导入组件组件
import TextBus from "@components/edit/TextBus";

// 注册组件
components:{
    TextBus
},


// 提交表单的时候获取结果
this.form.content = this.$refs.edit.getHtml();
<template>
    <div>
        <div id="editor"></div>
        <!--        <p>编辑器使用说明:该编辑器支持<a href="https://www.runoob.com/markdown/md-tutorial.html" target="_blank">markdown</a>语法,截图或本地图片,直接复制粘贴即可.</p>-->
    </div>
</template>

<script>
    import { createEditor } from '@textbus/textbus';
    import '@textbus/textbus/bundles/textbus.min.css';
    import { uploadImage } from '@/api/common';

    let editor = null;

    export default {
        name: 'Textbus',
        props: {
            // 可选 'dark' | 'mac-os' | 'mac-os-dark',不传即为默认样式
            theme: {
                type: String,
                default: () => 'dark'
            },
            content: {
                type: String,
                default: () => ``
            }
        },
        data () {
            return {
                data: '' // 编辑器最终的内容
            }
        },
        watch: {
            content: function (newVal) {
                this.data = newVal;
                this.setContent();
            }
        },
        mounted () {
            let that = this;
            editor = createEditor('#editor', {
                theme: 'dark', // 可选 'dark' | 'mac-os' | 'mac-os-dark',不传即为默认样式
                // type: string, prevValue?: string): string | Promise<string> | Observable<string>
                uploader (uploadType, prevValue) {
                    switch (uploadType) {
                    case 'video':
                        alert('不支持视频上传');
                        // console.log('上传视频');
                        break;
                    case 'image':
                        // prevValue 图片的二进制文件
                        const fileInput = document.createElement('input');
                        fileInput.setAttribute('type', 'file');
                        fileInput.setAttribute('accept', 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon');
                        fileInput.style.cssText = 'position: absolute; left: -9999px; top: -9999px; opacity: 0';
                        const promise = new Promise(resolve => {
                            fileInput.addEventListener('change', event => {
                                const form = new FormData();
                                for (const file of event.target.files) {
                                    form.append('file', file);
                                    form.append('type', 'image');
                                }
                                document.body.removeChild(fileInput);
                                uploadImage(form).then(res => {
                                    resolve(res.data.url);
                                });
                            })
                        }, false);
                        document.body.appendChild(fileInput);
                        fileInput.click();
                        return promise;
                        // eslint-disable-next-line no-unreachable
                        break;
                    case 'audio':
                        alert('请选择图片上传');
                        // console.log('不支持音频上传');
                        break;
                    default:
                        alert('请选择图片文件');
                        break;
                    }
                },
                contents: that.content
            });
            editor.onChange.subscribe(() => {
                that.data = editor.getContents().content;
            });
        },
        methods: {
            setContent () {
                editor.setContents(this.data);
            }
        }
    }
</script>

wangedit编辑器

<WangEdit v-if="" :content="content" ref="edit"></WangEdit>
import WangEdit from "@/components/edit/WangEdit";

components: {
        WangEdit
    },

// 设置内容
this.$refs.edit.setContent(this.form.content)

// 提交表单的时候获取结果
this.form.content = this.$refs.edit.getHtml();

局部打印

<template>
    <div>
        <div ref="container">
            <p>打印区域</p>
            <p>打印区域</p>
            <p>打印区域</p>
        </div>
        <Button @click="handlePrint">打印</Button>
    </div>
</template>
<script>
    export default {
        methods: {
            handlePrint () {
                this.$Print(this.$refs.container);
            }
        }
    }
</script>

API

$Print(el, options):

  • elElement 要打印区域的 DOM 节点

  • options:Object

    额外的配置项

    • beforeStartFunction 打印前的回调
    • finishFunction 打印完成的回调
    • backgroundColorString 设置打印区域背景色
    • 1.1.0 pageWidth:页面宽,当打印页面不足以显示时,可以指定 pageWidth,如 100%,让其适应。
    • 1.1.0 pageHeight:页面高。

如果需要忽略某个节点,只需要给这个节点设置 class 类名 i-print-hidden

二维码生成

https://www.npmjs.com/package/vue-qr

 <VueQr text="http://baidu.com" logoSrc="https://doc.orangbus.cn/orangbus.png" :size="300" />
import VueQr from "vue-qr";

 components:{
        VueQr
    },

表单提交字段处理

 created() {
      this.keys = Object.keys(this.form);
    },
        
_.pick(this.form,Object.keys(this.formData))

格式化时间戳

this.$Date.unix(form.expire_time).format('YYYY-MM-DD HH:mm:ss');

 formatDate(timestamp){
     return this.$Date.unix(timestamp).format('YYYY-MM-DD');
 },
     
formatDate(timestamp){
     return this.$Date.unix(timestamp).format('YYYY-MM-DD  HH:mm:ss');
 },

选择人员

 <DepUserList
              ref="depUserList"
              :userIds="[]"
              @getUserList="getUserList"
              ></DepUserList>
import DepUserList from '@/components/common/DepUserList';

getUserList(userList) {
            this.userList = userList;
            console.log(userList)
        },

机构选择

单选

多选

表格

<Table
       ref="table"
       :columns="tableColumns"
       :data="list"
       :loading="loading"
       :size="tableSize"
       class="ivu-mt"
       @on-sort-change="handleSortChange"
       @on-filter-change="handleFilterChange"
       @on-select="handleSelect"
       @on-selection-change="selectChange"
       @on-select-cancel="handleSelectCancel"
       @on-select-all="handleSelectAll"
       @on-select-all-cancel="handleSelectAllCancel"
       >
    <template slot-scope="{ row }" slot="title">
        <div @click="bigPic(row.pic)">
            <Avatar :src="row.pic" shape="square" size="large" slot="avatar"/>
            {{ row.title }}
        </div>
    </template>
    <template slot-scope="{ row }" slot="cate">
        {{ row.cate ? row.cate.name : '' }}
    </template>
    <template slot-scope="{ row }" slot="user">
        {{ row.user ? row.user.name : '' }}
    </template>

    <template slot-scope="{ row }" slot="status">
        <Badge v-if="row.status === 1" status="success" text="开启"/>
        <Badge v-if="row.status === 2" status="error" text="关闭"/>
    </template>

    <template slot-scope="{ row, index }" slot="action">
        <a @click="showDetail(row)">详情</a>
        <Divider type="vertical"/>
        <a @click="handleUpdate(index)">编辑</a>
        <Divider type="vertical"/>
        <a @click="del(index)">删除</a>
    </template>
</Table>
<div class="ivu-mt ivu-text-center">
    <Page
          :total="total"
          :current.sync="current"
          show-total
          show-sizer
          :page-size="size"
          @on-change="changePage"
          @on-page-size-change="handleChangePageSize"
          />
</div>
// 过滤条件改变时触发
        handleFilterChange() {
            // 从第一页开始
            this.current = 1;
        },
        // 选中一项,将数据添加至已选项中
        handleSelect(selection, row) {
            this.selectedData.push(row);
        },
        // 选项发生改变时
        selectChange(selection){
            this.selectedData = selection;
          console.log( this.selectedData)
        },
        // 取消选中一项,将取消的数据从已选项中删除
        handleSelectCancel(selection, row) {
            const index = this.selectedData.findIndex(item => item.name === row.name);
            this.selectedData.splice(index, 1);
        },
        // 当前页全选时,判断已选数据是否存在,不存在则添加
        handleSelectAll(selection) {
            console.log(selection)
            selection.forEach(item => {
                if (this.selectedData.findIndex(i => i.name === item.name) < 0) {
                    this.selectedData.push(item);
                }
            });
        },
        // 取消当前页全选时,将当前页的数据从已选项中删除
        handleSelectAllCancel() {
            const selection = this.list;
            selection.forEach(item => {
                const index = this.selectedData.findIndex(i => i.name === item.name);
                if (index >= 0) {
                    this.selectedData.splice(index, 1);
                }
            });
        },
computed: {
        labelWidth() {
            return this.isMobile ? undefined : 100;
        },
        labelPosition() {
            return this.isMobile ? 'top' : 'right';
        },
        
        // 动态设置列
        tableColumns() {
            const columns = [...this.columns];
            return columns.filter(item => item.show);
        }
    }

样式

```html

<span class="list-goods-list-item-price">价格</span>

<span class="list-goods-list-item-title">标题</span>

<span class=“list-goods-list-item-price>价格</span>

<span class="list-goods-list-item-desc">描述</span>

<span v-color="'#EA5455'">温馨提示:本产品为虚拟产品,一经购买……</span>

下拉分组

ui-select-group

<FormItem label="分类" prop="cate_id">
    <Select v-model="form.cate_id" placeholder="请选择" @on-change="handleSubmit()">
        <Option value="-1">不限</Option>
        <OptionGroup v-for="(cate,index) in cateList" :key="index" :label="cate.name">
            <Option v-for="(item,cate_index) in cate.children" :value="item.id" :key="cate_index">{{ item.name }}</Option>
        </OptionGroup>
    </Select>
</FormItem>

活动分类

@activity_cate

 <FormItem label="活动" prop="activity">
    <Select v-model="form.activity_id" placeholder="请选择">
        <Option value="">不限</Option>
        <Option v-for="(item,index) in activityList" :key="index" :value="item.id">
            {{ item.name }}
        </Option>
    </Select>
</FormItem>
<TableForm ref="tableForm" @on-submit="getData" @on-reset="search"></TableForm>

修改 props 传递参数

1、子组件改变,父组件更新

父组件

<template>
    <div>
        <PropsChild v-bind:content.sync="parentContent"></PropsChild>
        <!-- 给v-bind添加了sync,那么子组件中就有一个事件可以触发 update:xxx自定义事件并且传递要修改的值 -->
    </div>
</template>
<script>
    import PropsChild from './component/PropsChild.vue'
    export default {
        data() {
            return {
                parentContent:'我是父组件的数据********'
            }
        },
        components:{
            PropsChild
        }
    }
</script>

子组件

<template>
    <div>
        <button @click="btnTest">我是子组件,{{ lasterContent }}</button>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                lasterContent: this.content
            }
        },
        props:{
            content:{
                type:String
            }
        },
        watch: {
            content(val) {
                this.lasterContent = val;
            }
        },
        methods: {
            btnTest() {
                this.lasterContent = '哈哈,在子组件中改变了父组件传递过来的数据';
                this.$emit('update:content',this.lasterContent);
            }
        },
    }
</script>

2、子组件使用传递参数并改变

父组件


子组件

computed:{
   msg2(){
       return this.msgVal
   } 
},

yarn安装

npm install --global yarn

错误处理

  1. If you have node_modules folder and package-lock.json file in your root directory then remove those:

    rm -r node_modules
    rm package-lock.json
    
  2. Then run commands:

    npm install --save --legacy-peer-deps
    npm audit fix --force
    
  3. Create .env file in the root directory and paste below code:

    SKIP_PREFLIGHT_CHECK=true
    
  4. Now, start your project:

    npm start
    

npm install -g node-gyp

# before installing node-gyp on windows
npm install --global --production windows-build-tools

# install node-gyp globally
npm install -g node-gyp
 npm install grpc --save
 npm install node-pre-gyp --save

Vue错误处理

总是报Expected indentation of 0 spaces but found 2如何解决

.eslintrc.js 文件后 添加一下信息,并且重启

"indent": ["off", 2]

error: Unexpected trailing comma (comma-dangle)

解决方法: 在项目根目录下创建.prettierrc文件进行配置 .prettierrc文件:

{
  "semi": false,//格式化时不加分号 
  "singleQuote": true,//用单引号替换双引号
  "trailingComma":none//对象后面默认添加逗号
}

报错:error: Unexpected trailing comma (comma-dangle) at src\components\Login.vue:99:4: 解决: 配置 “trailingComma”:none

error: Newline required at end of file but not found (eol-last)

不需要遵循时间

// 缓存key
public function getCacheValue()
{
    $time = time();
    $notice = Notice::find($this->notice_id);
    $this->notice = $notice; // 不需要遵循时间
    $cacheKey = $this->getCacheKey();
    if (!Cache::has($cacheKey)) {
        // Carbon::parse("2021-04-5")->getTimestamp()
        Cache::put($cacheKey, $time, 86400);
    }
    return Cache::get($cacheKey);
}
$time = $this->getCacheValue();

Cache::put($this->getCacheKey(), $item['updated_at'], 86400);
$this->notice->time = $item['updated_at'];

Cache::forever($cacheKey, $time);
Cache::put($this->getCacheKey(), $item['updated_at'], 86400);
// ...mapActions('admin/user', [
//   'getUserInfo','setMenuList'
// ]),

图片选择器

 <!--    图片管理器-->
    <Modal
        draggable
        v-model="detail"
        title="选择图片"
        :fullscreen="true"
        :transfer="true"
        @on-ok="confirm"
       >
        <MinioCloudManage v-if="detail"></MinioCloudManage>
    </Modal>
    
    
  import MinioCloudManage from "@/pages/admin/cloud/comon/MinioCloudManage.vue";
  
  
 detail : true,
 
 confirm(){

            },

表格全屏

table-full

 <div class="ivu-inline-block ivu-fr">
                <Dropdown @on-click="handleChangeTableSize" trigger="click">
                    <Tooltip class="ivu-ml" content="密度" placement="top">
                        <i-link>
                            <Icon type="md-list" />
                        </i-link>
                    </Tooltip>
                    <DropdownMenu slot="list">
                        <DropdownItem name="default" :selected="tableSize === 'default'">默认</DropdownItem>
                        <DropdownItem name="large" :selected="tableSize === 'large'">宽松</DropdownItem>
                        <DropdownItem name="small" :selected="tableSize === 'small'">紧凑</DropdownItem>
                    </DropdownMenu>
                </Dropdown>
                <Tooltip class="ivu-ml" :content="tableFullscreen ? '退出全屏' : '全屏'" placement="top">
                    <i-link @click.native="handleFullscreen">
                        <Icon :custom="tableFullscreen ? 'i-icon i-icon-exit-full-screen' : 'i-icon i-icon-full-screen'" />
                    </i-link>
                </Tooltip>
                <Tooltip class="ivu-ml" content="刷新" placement="top">
                    <i-link @click.native="handleRefresh">
                        <Icon custom="i-icon i-icon-refresh" />
                    </i-link>
                </Tooltip>
                <Dropdown trigger="click">
                    <Tooltip class="ivu-ml" content="列设置" placement="top">
                        <i-link>
                            <Icon type="md-options" />
                        </i-link>
                    </Tooltip>
                    <DropdownMenu slot="list">
                        <div class="ivu-p-8">
                            <Row>
                                <Col span="12">列展示</Col>
                                <Col span="12" class="ivu-text-right">
                                    <i-link link-color @click.native="handleResetColumn">重置</i-link>
                                </Col>
                            </Row>
                        </div>
                        <Divider size="small" class="ivu-mt-8 ivu-mb-8" />
                        <li class="ivu-dropdown-item" v-for="item in columns" :key="item.title" v-if="item.title" @click="item.show = !item.show">
                            <Checkbox v-model="item.show"></Checkbox>
                            <span>{{ item.title }}</span>
                        </li>
                    </DropdownMenu>
                </Dropdown>
            </div>
tableSize: 'default',
tableFullscreen: false,
                
  handleChangeTableSize (size) {
        this.tableSize = size;
    },
    // 表格全屏
    handleFullscreen () {
        this.tableFullscreen = !this.tableFullscreen;
        if (this.tableFullscreen) {
            screenfull.request(this.$refs.card.$el);
        } else {
            screenfull.exit();
        }
    },
    // 刷新表格数据
    handleRefresh () {
        this.getData();
    },
    // 重置表格列设置
    handleResetColumn () {
        this.columns = this.columns.map(item => {
            const newItem = item;
            newItem.show = true;
            return newItem;
        });
    },              

表格公共方法

/**
 * 表格 tableMixins.js
 * */
export default {
    data(){
        return{
            loading: false,
            list: [],
            selectedData: [],
            page:1,
            limit: 10,
            total: 0,

            fields:{}, // 允许提交的字段
            form:{},
            formRules:{},
        }
    },
    methods: {
        search(){
            this.page = 1;
            this.getData();
        },

        // 选中一项,将数据添加至已选项中
        handleSelect (selection, row) {
            this.selectedData.push(row);
        },
        // 取消选中一项,将取消的数据从已选项中删除
        handleSelectCancel (selection, row) {
            const index = this.selectedData.findIndex(item => item.id === row.id);
            this.selectedData.splice(index, 1);
        },
        // 当前页全选时,判断已选数据是否存在,不存在则添加
        handleSelectAll (selection) {
            selection.forEach(item => {
                if (this.selectedData.findIndex(i => i.id === item.id) < 0) {
                    this.selectedData.push(item);
                }
            });
        },
        // 取消当前页全选时,将当前页的数据(即 dataWithPage)从已选项中删除
        handleSelectAllCancel () {
            this.selectedData = [];
        },
        // 清空所有已选项
        handleClearSelect () {
            this.selectedData = [];
        },
        // 切换页码
        changePage(page) {
            this.page = page;
            this.getData();
        },
        // 切换每页条数
        changeLimit(limit) {
            this.limit = this.limit;
            this.getData();
        },
        // 上一页
        prevPage (page) {
            this.page = page;
            this.getData();
        },
        // 下一页
        nextPage (page) {
            this.page = page;
            this.getData();
        }
    },
    computed: {
        // 动态设置列
        tableColumns () {
            const columns = [...this.columns];
            return columns.filter(item => item.show);
        }
    },
}

折现图表

<script >
import echartMixins from "@/mixins/echartMixins";
import {registerUser, uploadMovie} from "@api/dashboard";

export default {
    mixins:[echartMixins],
    props:{
        grid:{
            type:Object,
            default:()=>{
                return {
                    xl: 24,
                    lg: 24,
                    md: 24,
                    sm: 24,
                    xs: 24
                }
            }
        },
        height:{
            type:Number,
            default:()=>300
        },
        title:{
            type:String,
            default:()=>""
        },
    },
    mounted() {
        this.getData();
    },
    methods:{
        getData(){
            uploadMovie().then(res=>{
                if (res.code === 200){
                    let xaxis = [];
                    let series = [];
                   res.data.forEach(item=>{
                       xaxis.push(item.date);
                       series.push(item.total)
                   })
                    let seriesList = [
                        {
                            name: '更新数量',
                            data: series
                        }
                    ];
                    this.setChart(this.$refs.registerChart,xaxis,seriesList)
                }
            });
        }
    }
}
</script>

<template>
<div>
    <Col v-bind="grid">
        <h4>{{ title }}</h4>
        <div ref="registerChart" v-height="height"></div>
    </Col>
</div>
</template>

<style scoped lang="less">

</style>
/**
 * 折现统计 echartMixins.js
 * 使用方式
 *   this.setChart(this.$refs.visitChart,this.dayList,seriesList);
 *   dayList:[1,2,3,....]
 *   seriesList:[
	 {
       name: '标题',
       data:[1,2,3,....]
     }
 ]
 * */
import echarts from 'echarts';

export default {
	data() {
		return {
			visitChart: null,
		}
	},
	methods: {
		setChart(ref, xaxis = [], series = []) {
			let seriesData = series.map(item => {
				return {
					name: item.name,
					data: item.data,
					type: 'line', // bar
					tooltip: true,
					smooth: true,
					symbol: 'none',
					itemStyle: {
						normal: {
							barBorderRadius: [3, 3, 0, 0],
							color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
								{
									offset: 0,
									color: '#69cdff'
								},
								{
									offset: 0.5,
									color: '#3eb3f7'
								},
								{
									offset: 1,
									color: '#1495eb'
								}
							])
						}
					},
					areaStyle: {
						normal: {
							opacity: 0.2
						}
					}
				}
			})

			this.visitChart = echarts.init(ref);
			this.visitChart.setOption(
					{
						xAxis: {
							type: 'category',
							axisLine: {
								lineStyle: {
									color: '#D7DDE4'
								}
							},
							axisTick: {
								alignWithLabel: true,
								lineStyle: {
									color: '#D7DDE4'
								}
							},
							axisLabel: {
								textStyle: {
									color: '#7F8B9C'
								}
							},
							splitLine: {
								show: false,
								lineStyle: {
									color: '#F5F7F9'
								}
							},
							data: xaxis,
						},
						yAxis: {
							axisLine: {
								show: false
							},
							axisTick: {
								show: false
							},
							axisLabel: {
								textStyle: {
									color: '#7F8B9C'
								}
							},
							splitLine: {
								show: true,
								lineStyle: {
									color: '#F5F7F9'
								}
							},
							type: 'value'
						},
						series: seriesData,
						color: ['#1495EB', '#00CC66', '#F9D249', '#ff9900', '#9860DF'],
						grid: {
							left: 16,
							right: 25,
							bottom: 5,
							top: 20,
							containLabel: true
						},
						tooltip: {
							trigger: 'axis'
						}
					}
			);
		},
		handleResize() {
			this.visitChart.resize();
		},
	},
	beforeDestroy() {
		if (this.visitChart) {
			this.visitChart.dispose();
			this.visitChart = null;
		}
	}
}

消息提示

/**
 * 表格 messageMixins.js
 * */
export default {
    data(){
        return{

        }
    },
    methods: {
        resultMsg(res,status=200){
            let {code,msg} = res;
            return code === status ? this.$Message.success(msg) : this.$Message.error(msg);
        }
    }
}
drawer: {
                show: false,
                type: 'edit', // edit || read || new
                styles: {
                    height: 'calc(100% - 55px)',
                    overflow: 'auto',
                    paddingBottom: '53px',
                    position: 'static'
                }
            },

校区搜索

 <Modal
    v-model="modal"
    title="校区选择"
     width="800"
    :loading="submitting"
    :fullscreen="false"
    :transfer="true"
    :draggable="true"
    footer-hide
    >
    <OrgSchoolList v-if="modal" @getSchool="getSchool"></OrgSchoolList>
</Modal>
import OrgSchoolList from "@/components/common/OrgSchoolList.vue";

getSchool(school){
    this.modal = false;
     console.log(school)
},