GuoYuFu123 il y a 6 ans
Parent
commit
867fa4b5ad

+ 27 - 0
src/api/alarm/alarm.js

@@ -4,6 +4,7 @@
 @info:alarm-api
  */
 import httputils from '@/utils/httputils'
+
 const api = {
     //获取对象类型
     getObjectType() {
@@ -89,6 +90,32 @@ const api = {
             )
         })
     },
+    // 获取对象类的改造成一个整的数组
+    getObjTypeNameFromCode(objType, category, spaceNameObj) {
+        if (objType == 'building') {
+            return { name: '建筑' }
+        } else if (objType == 'floor') {
+            return { name: '楼层' }
+        } else if (objType == 'space') {
+            let name
+            if (category) {
+                name = spaceNameObj[category]
+            } else {
+                name = '空间'
+            }
+
+            return { name: name }
+        } else {
+            let arr = objTypeArr.filter((ele, index) => {
+                return ele.code == category
+            })
+            if (arr.length) {
+                return arr[0]
+            } else {
+                return { name: '---' }
+            }
+        }
+    },
     // 获取对象类中的空间级联
     getObjTypeSpace() {
         return new Promise((resolve, reject) => {

+ 72 - 0
src/api/fm/rules.js

@@ -0,0 +1,72 @@
+/**
+@author:fugy
+@date:2019.1.16
+@info:项目抢单规则设定=project-rule-api
+ */
+const planHz = [
+    { id: 'd', name: '每日' },
+    { id: 'w', name: '每周' },
+    { id: 'm', name: '每月' },
+    { id: 'y', name: '每年' }
+]
+import httputils from '@/utils/httputils'
+const api = {
+    getLevelDef() {
+        return { value: 'id', label: 'name', children: 'content' }
+    },
+    //获取级别列表
+    getLevelList() {
+        return new Promise((resolve, reject) => {
+            httputils.getJson('/server/workorder/engineer/level/def/list', null, resp => {
+                let result = []
+                resp.content.forEach(item => {
+                    let temp = { id: item.skillId, name: item.name, content: [] }
+                    if (item.content) {
+                        item.content.forEach(level => {
+                            temp.content.push({ id: level.levelId, name: level.name })
+                        })
+                    }
+                    result.push(temp)
+                })
+                resolve(result)
+            })
+        })
+    },
+    // 获取工单类型列表
+    getOrderType() {
+        return new Promise(resolve => {
+            httputils.getJson('/server/workorder/rule/queryWoTypeList', {}, resp => {
+                if (resp.result == 'success' && resp.count) {
+                    resolve(resp.content)
+                } else {
+                    resolve([])
+                }
+            })
+        })
+    },
+    //获取计划频率
+    getPlanHz() {
+        return planHz
+    },
+    //获取项目抢单规则的列表数据
+    getListData(params) {
+        return new Promise(resolve => {
+            httputils.postJson('/server/workorder/rule/query', params, resp => {
+                if (resp.result == 'success' && resp.content.length) {
+                    resolve(resp.content)
+                } else {
+                    resolve([])
+                }
+            })
+        })
+    },
+    //配置当前的工单的规则
+    updateWorkOrder(params) {
+        return new Promise(resolve => {
+            httputils.postJson('/server/workorder/rule/createOrUpdate', params, resp => {
+                resolve(resp)
+            })
+        })
+    }
+}
+export default api

+ 83 - 0
src/api/fm/sop.js

@@ -0,0 +1,83 @@
+/**
+@author:fugy
+@date:2018.10.22
+@info:通用问题对应集团的sop的api
+ */
+import httputils from '@/utils/httputils';
+let priorityArr = [
+    //优先级数组
+    {
+        label: 'S',
+        value: 'S'
+    },
+    {
+        label: 'A',
+        value: 'A'
+    },
+    {
+        label: 'B',
+        value: 'B'
+    },
+    {
+        label: 'C',
+        value: 'C'
+    },
+    {
+        label: 'D',
+        value: 'D'
+    }
+];
+let problemArr = [
+    //问题级别数组
+    {
+        label: '电器',
+        value: '电器'
+    },
+    {
+        label: '建筑',
+        value: '建筑'
+    },
+    {
+        label: '家具',
+        value: '家具'
+    },
+    {
+        label: '其他',
+        value: '其他'
+    }
+]
+const api = {
+    // 获取sop的列表
+    getListData: function(params) {
+        return new Promise((resolve, reject) => {
+			httputils.postJson('/server/workorder/generalProblem/problem/query', params, res => {
+                resolve(res)
+			})
+		})
+    },
+    // 获取sop问题的列表数据
+    getSopList(params) {
+        return new Promise((resolve, reject) => {
+			httputils.postJson('/server/workorder/generalProblem/sop/list', params, res => {
+                resolve(res)
+			})
+		})
+    },
+    // 保存配置sop
+    setSop(params) {
+        return new Promise((resolve, reject) => {
+			httputils.postJson('/server/workorder/generalProblem/sop/set', params, res => {
+                resolve(res)
+			})
+		})
+    },
+    // 优先级数组
+    getPriorityArr: function () {
+        return priorityArr
+    },
+    // 获取问题类型
+    getProblemArr: function () {
+        return problemArr
+    },
+}
+export default api;

+ 1 - 1
src/framework/layout/PageHeader.vue

@@ -41,7 +41,7 @@ export default {
     props: [],
     data() {
         return {
-            selectedProjectId: null
+            selectedProjectId: 'Pj1101080002'
         }
     },
     computed: {

+ 1 - 1
src/framework/layout/layout-store.js

@@ -13,7 +13,7 @@ export default {
         userInfo: { username: 'admin' },
         permissions: {"system:role:delete": true, "system:role:create": true, "system:role:query": true, "system:role:setOpts": true},
         currentProjectId: null,
-        projects: [],
+        projects: [{name: '新华创新大厦',id: 'Pj1101080002'}],
         breadcrumb: []
     },
     getters: {

+ 2 - 1
src/framework/style/layout.scss

@@ -114,6 +114,7 @@ body {
         height: 100%;
         line-height: $pageHeaderHeight;
         display: flex;
+        justify-content: center;
         .menu-toggler {
             margin-right: 10px;
             .icon-arrows {
@@ -121,7 +122,7 @@ body {
                 width: 24px;
                 height: 24px;
                 margin-left: 10px;
-                line-height: 24px;
+                line-height: px;
                 text-align: center;
                 font-size: 20px;
             }

+ 11 - 3
src/framework/style/theme.scss

@@ -17,9 +17,17 @@ $themeColor: #5BA7FF;
                 background: #fff;
                 color: $themeColor;
             }
-            // .el-select .el-input--suffix .el-input__inner {
-            //     background: #e3e4e6;
-            // }
+            .el-select {   
+                .el-input--suffix .el-input__inner {
+                    background: $themeColor;
+                    color: #fff;
+                    border: none
+                }
+                .el-input .el-select__caret {
+                    color: #fff;
+                }
+            }
+            
         }
         .user-menu {
             .user-menu-dropdown {

+ 8 - 4
src/router/sagacloud.js

@@ -6,8 +6,12 @@ import ChangePwd from '@/views/system/pwd/ChangePwd'
 
 /** 报警设置 */
 const ProjAlarm = () => import('@/views/alarm/projalarm/index');
-const ProjNotice = () => import('@/views/alarm/notice/index')
-const StaffSetting = () => import('@/views/alarm/staff/index')
+const ProjNotice = () => import('@/views/alarm/notice/index');
+const StaffSetting = () => import('@/views/alarm/staff/index');
+
+/**与FM相关设置 */
+const ProjSop = () => import('@/views/fm/projectsop/index')
+const ProjRules = () => import('@/views/fm/projectrule')
 
 /**点位部分 */
 import pointConfig from '@/views/point/config_point'
@@ -63,8 +67,8 @@ export default [
         component: LayoutMain,
         children: [
             { path: '', name: 'Dasboard', component: Dasboard },
-            { path: 'sopsetting', name: 'Dasboard', component: Dasboard },
-            { path: 'rulesetting', name: 'Dasboard', component: Dasboard }
+            { path: 'sopsetting', name: 'Dasboard', component: ProjSop },
+            { path: 'rulesetting', name: 'Dasboard', component: ProjRules }
         ]
     },
     // 点位表管理

+ 283 - 0
src/views/fm/projectrule/edit.vue

@@ -0,0 +1,283 @@
+<template>
+    <el-dialog title='编辑规则' :visible.sync='dialogVisible' width='70%'>
+        <el-form :model='formValue' ref='ruleForm' label-width='180px' class='demo-ruleForm'>
+            <el-form-item label='计划名称'>
+                <span>{{itemData.plan_name||'--'}}</span>
+            </el-form-item>
+            <el-form-item label='计划类型'>
+                <span>{{itemData.order_type_name||'--'}}</span>
+            </el-form-item>
+            <el-form-item label='计划周期'>
+                <span>{{itemData.freq_cycle_desc||'--'}}</span>
+            </el-form-item>
+            <el-form-item
+                label='预计每次耗时'
+                prop='timeCost'
+                :rules='[{ required: true, message: "请输入预计总耗时", trigger:["blur"] },{validator: this.verifytimeCost, trigger: ["blur"] },]'
+            >
+                <el-input v-model.number='formValue.timeCost' style='width:10rem;'>
+                    <template slot='append'>分钟</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item
+                label='预计每次耗材费'
+                prop='itemCost'
+                :rules='[{ required: true, message: "请输入预计总耗材费", trigger:["blur"] },{validator: this.verifyitemCost, trigger: ["blur", "submit"] },]'
+            >
+                <el-input v-model.number='formValue.itemCost' style='width:10rem;'>
+                    <template slot='append'>元</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label='每次人工费合计'>
+                <span>{{countCost}}</span>
+            </el-form-item>
+            <el-form-item label='每次工单抢单人员限制' :rules='[{required: true}]'>
+                <el-row
+                    v-for='(item, index) in formValue.workOrderRuleStaffList'
+                    :key='index'
+                    style='margin-bottom: 5px'
+                >
+                    <el-col :span='6'>
+                        <el-form-item
+                            :prop='"workOrderRuleStaffList." + index + ".level"'
+                            :rules='[{ required: true, message: "请选择专业", trigger: "submit" },]'
+                            style='margin-right:10px;'
+                        >
+                            <el-cascader
+                                v-model='item.level'
+                                :options='specialtyLevelArr'
+                                @change='changeSkillLevel'
+                                :props='skillDef'
+                            ></el-cascader>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span='3'>
+                        <el-form-item
+                            :prop='"workOrderRuleStaffList." + index + ".count"'
+                            :rules='[{ required: true, message: "请选择人数", trigger: "submit" },]'
+                            style='margin-right:10px;'
+                        >
+                            <el-select v-model='item.count'>
+                                <el-option v-for='item in allPeopleArr ' :key='item ' :label='item ' :value='item'></el-option>
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span='10'>
+                        <el-form-item
+                            label='每人费用'
+                            :prop='"workOrderRuleStaffList." + index + ".perCost"'
+                            :rules='[{ required: true, message: "请选择人均费用", trigger: "blur" }, { required: true, validator: verifyperCost, trigger:["blur",  "submit"] },]'
+                            style
+                        >
+                            <el-input v-model='item.perCost' placeholder>
+                                <template slot='append'>元</template>
+                            </el-input>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span='2' style='height:40px; display: flex;align-items: center;justify-content: flex-end;'>
+                        <el-button size='small' v-if='index == 0' @click='addgrablimiting' style='height:82%;'>
+                            <i class='el-icon-circle-plus'></i>
+                        </el-button>
+                        <el-button
+                            size='small'
+                            v-if='index > 0'
+                            @click='delCol(item)'
+                            style='height:82%;color:#F56C6C;'
+                        >
+                            <i class='el-icon-circle-close'></i>
+                        </el-button>
+                    </el-col>
+                </el-row>
+            </el-form-item>
+        </el-form>
+        <p class='btn-box'>
+            <el-button @click='dialogVisible = false'>取 消</el-button>
+            <el-button class='save' type='primary' @click='submitEditorRule'>保 存</el-button>
+        </p>
+    </el-dialog>
+</template>
+
+<script>
+import api from '@/api/fm/rules'
+export default {
+    name: 'project-rule-edit',
+    data() {
+        return {
+            dialogVisible: false,
+            allPeopleArr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+            formValue: {
+                timeCost: '',
+                itemCost: '',
+                workOrderRuleStaffList: [{ level: [0, 0], count: 1, perCost: null }]
+            },
+            specialtyLevelArr: [],
+            skillDef: api.getLevelDef(),
+            itemData: {}
+        }
+    },
+    computed: {
+        countCost() {
+            if (this.formValue.workOrderRuleStaffList) {
+                let cost = 0
+                this.formValue.workOrderRuleStaffList.forEach(staff => {
+                    cost += staff.count * staff.perCost
+                })
+                return cost == 0 ? '根据以下设定的人数和每人费用自动统计' : cost.toFixed(2)
+            } else {
+                return '根据以下设定的人数和每人费用自动统计'
+            }
+        }
+    },
+    methods: {
+        // opt:['create' | 'edit']
+        async show(item, opt) {
+            this.dialogVisible = true
+            this.itemData = item
+            this.initForm()
+            this.resetForm()
+            if (opt == 'edit') {
+                let params = {
+                    project_id: item.projectId,
+                    plan_id: item.plan_id
+                }
+                let res = await api.getListData(params)
+                this.formValue.itemCost = res[0].itemCost
+                this.formValue.timeCost = res[0].timeCost
+                this.formValue.id = res[0].ruleId
+                res[0].workOrderRuleStaffList.forEach(item => {
+                    item.level = [item.skillId, item.levelId]
+                })
+                this.formValue.workOrderRuleStaffList = res[0].workOrderRuleStaffList                
+            }
+            this.changeSkillLevel()
+        },
+        verifytimeCost(rule, value, callback) {
+            //验证总耗时
+            value = value.toString()
+            let reg = /^[1-9]\d{0,2}$/
+            if (reg.test(value)) {
+                callback()
+            } else {
+                return callback(new Error('只支持3位的正整数!'))
+            }
+        },
+        verifyitemCost(rule, value, callback) {
+            //验证耗材费
+            let reg = /^\d{0,8}\.{0,1}(\d{1,2})?$/ //小数点1-2
+            value = value.toString()
+            if (reg.test(value)) {
+                //空串转字符串为0
+                callback()
+            } else {
+                return callback(new Error('只支持最多2位小数长度在10以内正数!'))
+            }
+        },
+        verifyperCost(rule, value, callback) {
+            //验证每人费用
+            let reg = /^\d{0,8}\.{0,1}(\d{1,2})?$/ //小数点1-2
+            value = value.toString()
+            if (reg.test(value)) {
+                //空串转字符串为0
+                callback()
+            } else {
+                return callback(new Error('只支持最多2位小数长度在10以内正数!'))
+            }
+        },
+
+        changeSkillLevel() {
+            let tmp = {}
+            this.formValue.workOrderRuleStaffList.forEach(staff => {
+                tmp[staff.level[0]] = true
+            })
+            this.specialtyLevelArr.forEach(skill => {
+                if (tmp[skill.id]) {
+                    skill.disabled = true
+                } else {
+                    skill.disabled = false
+                }
+            })
+        },
+        addgrablimiting() {
+            this.formValue.workOrderRuleStaffList.push(this.getEmptyStaff())
+            this.changeSkillLevel()
+        },
+        getEmptyStaff() {
+            return { level: [], count: 1, perCost: '' }
+        },
+        delCol(item) {
+            let arr = this.formValue.workOrderRuleStaffList
+            arr.splice(arr.indexOf(item), 1)
+            this.changeSkillLevel()
+        },
+        submitEditorRule() {
+            this.$refs['ruleForm'].validate(valid => {
+                if (valid) {
+                    let workOrderRuleStaffList = []
+                    this.formValue.workOrderRuleStaffList.forEach(item => {
+                        workOrderRuleStaffList.push({
+                            perCost: item.perCost,
+                            count: item.count,
+                            skillId: item.level[0],
+                            levelId: item.level[1]
+                        })
+                    })
+                    let params = {
+                        id: this.formValue.id || undefined,
+                        planId: this.itemData.plan_id,
+                        itemCost: this.formValue.itemCost,
+                        timeCost: this.formValue.timeCost,
+                        workOrderRuleStaffList: workOrderRuleStaffList
+                    };
+                    console.log(params)
+                    console.log(JSON.stringify(params))
+                    // return false;
+                    api.updateWorkOrder(params).then(res => {
+                        if (res.result == 'success') {
+                            this.$message({
+                                message: '保存成功',
+                                type: 'success'
+                            })
+                            this.dialogVisible = false
+                            this.$emit('refresh')
+                        }
+                    })
+                } else {
+                    this.$message.error('请完成所有必填项!')
+                }
+            })
+        },
+        resetForm() {
+            this.$nextTick(() => {
+                this.$refs['ruleForm'].resetFields()
+            })
+        },
+        initForm() {
+            this.formValue = {
+                timeCost: null,
+                itemCost: null,
+                workOrderRuleStaffList: [{ level: [0, 0], count: 1, perCost: null }]
+            }
+        },
+        initLevelArr() {
+            // this.initForm()
+            api.getLevelList().then(levelList => {
+                this.specialtyLevelArr = [{ id: 0, name: '无限制', content: [{ id: 0, name: '无限制' }] }].concat(
+                    levelList
+                )
+            })
+        }
+    },
+    mounted() {
+        this.initLevelArr()
+    }
+}
+</script>
+
+<style lang='less' scoped>
+.btn-box {
+    text-align: center;
+    .save {
+        margin-left: 50px;
+    }
+}
+</style>

+ 198 - 0
src/views/fm/projectrule/index.vue

@@ -0,0 +1,198 @@
+<template>
+    <div>
+        <div class='condition'>
+            <div class='top'>
+                <sg-selector type='project' @changed='projectedSelected'></sg-selector>
+                <el-input style='width: 400px;' v-model.trim='searchValue' placeholder='输入计划名称关键字进行查询' clearable></el-input>
+                <el-button type='primary' @click='search'>查询</el-button>
+            </div>
+            <hr class='line'>
+            <div class='bottom'>
+                <p>
+                    <span>计划频率</span>
+                    <el-select v-model='planHzValue' placeholder='全部' @change='planChange'>
+                        <el-option v-for='(item,index) in planHzArr' :key='index' :label='item.name' :value='item.id'></el-option>
+                    </el-select>
+                </p>
+                <p>
+                    <span>工单类型</span>
+                    <el-select v-model='orderValue' placeholder='全部' @change='orderChange'>
+                        <el-option
+                            v-for='(item,index) in orderTypeArr'
+                            :key='index'
+                            :label='item.name'
+                            :value='item.code'
+                        ></el-option>
+                    </el-select>
+                </p>
+                <p class='check-box'>
+                    <el-checkbox v-model='checked' @change='checkBoxChange'>只看尚未设置抢单规则的计划</el-checkbox>
+                </p>
+            </div>
+        </div>
+        <div class='table'>
+            <el-table :data='tableData' style='width: 100%' border v-loading='loading'>
+                <el-table-column prop='order_type_name' label='工单类型' header-align='center' width="120"></el-table-column>
+                <el-table-column prop='freq_cycle_desc' label='计划周期' header-align='center' width="150"></el-table-column>
+                <el-table-column prop='plan_name' label='计划名称' header-align='center'></el-table-column>
+                <el-table-column prop='perCostStr' label='抢单人员限制及每人费用' header-align='center'></el-table-column>
+                <el-table-column label='耗材费' header-align='center' width="120">
+                     <template slot-scope='scope'>
+                        <span>{{scope.row.hasOrderRule ?(scope.row.itemCost + '元') : ''}}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label='预计每次耗时' header-align='center' width="120">、
+                    <template slot-scope='scope'>
+                        <span>{{ scope.row.hasOrderRule ? (scope.row.timeCost + '分钟') : ''}}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column width='100' label='操作' header-align='center'>
+                    <template slot-scope='scope'>
+                        <el-button v-if='scope.row.hasOrderRule' type='text' @click='edit(scope.row, "edit")'>编辑</el-button>
+                        <el-button v-else class='red' type='text' @click='edit(scope.row, "create")'>待设置</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </div>
+        <!-- components -->
+        <v-edit ref='edit' @refresh='refreshList'></v-edit>
+    </div>
+</template>
+
+<script>
+import vEdit from './edit'
+//api
+import api from '@/api/fm/rules'
+export default {
+    name: 'project-rule',
+    data() {
+        return {
+            loading: false,
+            searchValue: '',
+            planHzArr: [],
+            planHzValue: '',
+            orderTypeArr: [],
+            orderValue: '',
+            checked: false,
+            tableData: [],
+            /***Dict**** */
+            majorObj: {},
+            levelObj: {}
+        }
+    },
+    components: {
+        vEdit
+    },
+    methods: {
+        //项目改变
+        projectedSelected(val) {
+            this.projectId = val
+            this.getList()
+        },
+        planChange() {
+            this.getList()
+        },
+        orderChange() {
+            this.getList()
+        },
+        search() {
+            this.getList()
+        },
+        checkBoxChange(val) {
+            this.getList()
+        },
+        //获取list数据
+        async getList() {
+            this.loading = true;
+            let hasOrderRule = this.checked ? 0 : undefined
+            let params = {
+                project_id: this.projectId,
+                freq_cycle: this.planHzValue || undefined,
+                order_type: this.orderValue || undefined,
+                plan_name: this.searchValue || undefined,
+                hasOrderRule: hasOrderRule
+            }
+            let res = await api.getListData(params)
+            res.forEach(item => {
+                if (item.hasOrderRule) {
+                    let str = ''
+                    item.workOrderRuleStaffList.length
+                        ? item.workOrderRuleStaffList.forEach(staff => {
+                              let strChunk = `${staff.skillId ? this.majorObj[staff.skillId] : '无限制'}${
+                                  staff.levelId ? this.levelObj[staff.levelId] : ''
+                              }${staff.count}人(每人${staff.perCost}元) ,`
+                              str = str + strChunk
+                          })
+                        : ''
+                    str = str.substring(0, str.length-1)
+                    item.perCostStr = str
+                }
+            })
+            this.tableData = res
+            this.loading = false;
+        },
+        edit(item, opt) {
+            item.projectId = this.projectId
+            this.$refs.edit.show(item, opt)
+        },
+        refreshList() {
+            this.getList()
+        },
+        async init() {
+            //获取工单类型
+            this.orderTypeArr = await api.getOrderType()            
+            this.orderTypeArr.unshift({ name: '全部', id: '' })
+            //获取计划频率
+            let planHzArr = [{ name: '全部', id: '' }, ...api.getPlanHz()]
+            this.planHzArr = planHzArr
+            //缓存专业等级
+            let res = await api.getLevelList()
+            var majorObj = {}
+            var levelObj = {}
+            if (res.length) {
+                res.forEach(major => {
+                    majorObj[major.id] = major.name
+                    if (major.content && major.content.length) {
+                        major.content.forEach(level => {
+                            levelObj[level.id] = level.name
+                        })
+                    }
+                })
+            }
+            this.majorObj = majorObj
+            this.levelObj = levelObj
+        }
+    },
+    created() {
+        this.init()
+    }
+}
+</script>
+
+<style lang='less' scoped>
+.red {
+    color: red;
+}
+.line {
+    background-color: #ccc;
+    height: 1px;
+    border: none;
+}
+.condition {
+    .bottom {
+        font-size: 16px;
+        color: #606266;
+        overflow: hidden;
+        p {
+            float: left;
+            margin-right: 20px;
+        }
+        .check-box {
+            line-height: 40px;
+        }
+    }
+}
+.table {
+    margin-top: 10px;
+}
+</style>

+ 174 - 0
src/views/fm/projectsop/edit.vue

@@ -0,0 +1,174 @@
+/**
+@author:fugy
+@date:2018.10.24
+@info:项目sop编辑和配置页面
+ */
+ <template>
+<div v-if="itemData">
+    <div class="top">
+        <el-button size="medium" @click="goBack()">返回</el-button>
+        <el-button type="primary" size="medium" @click="save()">保存</el-button>
+    </div>
+    <hr class="line" />
+    <div class="item-info">
+        <p><span>问题名称 : </span><span>{{itemData.name}}</span></p>
+        <p><span>问题编号 : </span><span>{{itemData.serialId}}</span></p>
+        <p><span>问题类型 : </span><span>{{itemData.type}}</span></p>
+        <p><span>优先级 : </span><span>{{itemData.priority}}</span></p>
+        <!-- <p><span>适用建筑功能类型 : </span><span>{{"12312313"}}</span></p> -->
+        <p><span>问题详述 : </span><span>{{itemData.remark || "---"}}</span></p>
+        <div class="link-div">
+            <span class="left">关联的项目SOP : </span>
+            <div class="right"> 
+                <el-button size="medium" @click="selectSopHandle">点击选择</el-button>
+                <ul v-if="sopArr.length">
+                    <li v-for="(item, index) in sopArr" :key="index">
+                        <span class="sop-name">{{item.sopName}}</span>
+                        <i class="el-icon-error sop-icon-del" @click="delSopHandle(index)"></i>
+                    </li>
+                </ul>
+            </div>            
+        </div>        
+    </div>        
+    <!-- components -->
+    <v-select-sop 
+    :selectSopVisibleFlag="selectSopVisibleFlag"
+    :checkedSopArr="sopArr" 
+    :projectId="projectId"
+    @sop-checked="sopCheckedHandle">
+    </v-select-sop>
+</div>
+ </template>
+
+ <script>
+//  component
+import vSelectSop from  './selectsop'; //选择sop页面
+// api
+import api from "@/api/fm/sop"; 
+export default {
+    name: "sop-edit-page",
+    data() {
+        return {
+            selectSopVisibleFlag: false, //选择sop的弹窗flag
+            projectId:null, //项目id
+            itemData: null, //itemData,
+            sopArr:[], //sopArr
+        }
+    },
+    components: {
+        vSelectSop,
+    },
+    props:["editData","initFlag"],
+    methods: {
+        // 点击选择sop
+        selectSopHandle() {
+            this.selectSopVisibleFlag = !this.selectSopVisibleFlag;
+        },
+        // 返回
+        goBack() {
+            let refresh = false
+            this.$emit("to-list", refresh);
+        },
+        // 删除sop
+        delSopHandle(index) {
+            this.sopArr.splice(index, 1);
+        },
+        // 保存
+        async save() {
+            let sopArr = this.sopArr.map((ele, index) => {
+                return {sopId: ele.sopId}
+            });
+            let params = {
+                id: this.itemData.id,
+                projectId: this.projectId,
+                sopList: sopArr
+            }
+            let {result} = await api.setSop(params);
+            if(result === "success") {
+                this.$message({
+                    message: '保存成功',
+                    type: 'success'
+                });
+                // 跳转隐藏切换
+                let refresh = true;
+                this.$emit("to-list", refresh);
+            }
+            
+        },
+        /********************组件回传事件****************************** */
+        sopCheckedHandle(arr) {
+            this.sopArr = arr;
+        }
+    },
+    watch:{
+        editData(val) {
+            this.itemData = val
+            this.projectId = val.projectId;
+            this.sopArr = JSON.parse(JSON.stringify(val.sopList));
+        },
+        initFlag(val) {
+            this.projectId = this.editData.projectId;
+            this.sopArr = JSON.parse(JSON.stringify(this.editData.sopList));
+        }
+    }
+}
+ </script>
+
+ <style lang="less" scoped>
+ .top{
+     display: flex;
+     justify-content: space-between
+ }
+ .line {
+    background-color: #ccc;
+    height: 1px;
+    border: none;
+    margin: 10px 0
+}
+.item-info{
+    padding-left:20%;
+    font-size: 14px;
+    color: #5e6d82;
+    p{
+        padding: 10px 0;
+        overflow: hidden;
+        span {
+            float: left;
+        }
+        span:nth-of-type(1){
+            margin-right: 20px;
+        }
+    }
+    .link-div {
+        overflow: hidden;
+        .left, .right{
+            float: left;
+        }
+        .left {
+            padding-top: 8px;
+        }
+        .right {
+            margin-left: 20px;
+        }
+        li {
+            overflow: hidden;
+            width: 400px;
+            margin: 5px 0;
+            background-color: #cccccc;
+            padding: 5px 15px;
+            .sop-name {
+                float: left;
+            }
+            .sop-icon-del {
+                cursor: pointer;
+                float: right;
+                margin-top:3px;
+            }
+        }
+    }
+}
+
+    
+
+ </style>
+ 

+ 52 - 0
src/views/fm/projectsop/index.vue

@@ -0,0 +1,52 @@
+/**
+@author:fugy
+@date:2018.10.24
+@info:项目sop配置index(目的--保留编辑返回的当前列表页的信息)
+ */
+<template>
+<div>
+    <v-list ref="list" v-show="componentsName == 'vList'" @to-edit="toEditHandle"></v-list>
+    <v-edit 
+    v-show="componentsName == 'vEdit'" 
+    @to-list="toListHandle" 
+    :editData="editData" 
+    :initFlag="initFlag"></v-edit>
+</div>
+</template>
+<script>
+// component
+import vList from "./list"; //查看item弹窗
+import vEdit from "./edit"; //查看编辑页面
+export default {
+    name: "group-sop-index",
+    data() {
+        return {
+            componentsName: "vList",   //vList or vEdit
+            editData: null, //编辑数据,
+            initFlag: false, //目的让edit重新复制
+        }
+    },
+    components: {
+        vList,
+        vEdit
+    },
+    methods: {
+        // 去编辑页面
+        toEditHandle(row) {
+            this.componentsName = "vEdit";
+            this.initFlag = !this.initFlag;
+            this.editData = row;
+        },
+        // 去列表页面
+        toListHandle(refresh) {
+            this.componentsName = "vList";
+            //刷新列表页
+            if (refresh) {
+                this.$refs.list.getListData();
+            }            
+        }
+    }
+}
+</script>
+<style lang='less' scoped>
+</style>

+ 386 - 0
src/views/fm/projectsop/list.vue

@@ -0,0 +1,386 @@
+/**
+@author:fugy
+@date:2018.10.24
+@info:项目sop配置列表
+ */
+<template>
+<div>
+    <!-- 搜索框 -->
+    <div>   
+        <sg-selector type="project" @changed="projectedSelected"></sg-selector>
+        <el-input placeholder="输入问题名称、问题编号关键字进行查询" v-model.trim="searchValue" style="width:400px;" clearable></el-input>
+        <el-button type="primary" @click="getSearch">查询</el-button>
+    </div>
+    <hr class="line" /> 
+    <!-- 条件框 -->
+    <div class="condition-box">   
+        <p>
+            <span>优先级:</span>
+            <el-select v-model="priorityValue" size="medium" @change="priorityHandle">
+                <el-option
+                v-for="item in priorityArr"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value">
+                </el-option>
+            </el-select>
+        </p>
+        <p>
+            <span>问题类型:</span>
+            <el-select v-model="problemValue" size="medium" @change="problemHandle">
+                <el-option
+                v-for="item in problemArr"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value">
+                </el-option>
+            </el-select>
+        </p>
+        <p style="display:flex">
+                <span style="line-height: 40px;">对象类:</span>
+            <v-obj-type @change="objTypeChange"></v-obj-type>
+            <!-- <el-cascader
+				style="width: 300px;"
+                size="medium"
+				:options="objTypeOptions"
+				v-model="objTypeSelectArr"
+				@change="objTypeHandle">
+			</el-cascader> -->
+        </p>
+        <p class="check-box">
+            <el-checkbox v-model="checked" @change="isSopHandle">只看尚未配置项目SOP的</el-checkbox>
+        </p>
+    </div>
+    <!-- list表格 -->
+    <div class="table-box">
+        <template>
+            <el-table
+            :data="tableData"
+            style="width: 100%"
+            border>
+                <el-table-column
+                prop="serialId"
+                label="问题编号"
+                header-align="center"
+                width="150">
+                </el-table-column>
+                <el-table-column
+                prop="type"
+                label="问题类型"
+                header-align="center"
+                width="150">
+                </el-table-column>
+                <el-table-column
+                prop="objType"
+                header-align="center"
+                label="对象类"
+                width="200">
+                </el-table-column>
+                <el-table-column
+                prop="priority"
+                label="优先级"
+                header-align="center"
+                width="100">
+                </el-table-column>
+                <el-table-column
+                prop="name"
+                header-align="center"
+                label="问题名称">
+                </el-table-column>
+                <el-table-column
+                prop="sopLinkName"
+                label="关联的项目SOP"
+                header-align="center">
+                </el-table-column>
+                <el-table-column
+                header-align="center"
+                width="150"
+                label="操作">
+                    <template slot-scope="scope">
+                        <p style="text-align: center;">
+                            <el-button type="text" v-if="scope.row.sopLinkName" size="small" @click="getLook(scope.row)">查看</el-button>
+                            <el-button type="text" v-if="scope.row.sopLinkName" size="small" @click="edit(scope.row)">编辑</el-button>
+                            <el-button type="text" v-if="scope.row.sopLinkName == ''" size="small" class="config-btn" @click="toConfig(scope.row)">去配置 ></el-button>
+                        </p>                        
+                    </template>
+                </el-table-column>
+            </el-table>
+        </template>
+    </div>
+    <!-- 分页 -->
+    <div class="page-box" v-if="total">
+        <el-pagination
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="currentPage"
+        :page-sizes="[10, 20, 30, 50]"
+        :page-size="100"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="total">
+        </el-pagination>
+    </div>
+    <!-- vue-component -->
+    <!-- item查看弹窗 -->
+    <v-look-item :lookVisibleFlag="lookVisibleFlag" :itemInfoData="itemInfoData" @look-to-edit="lookToEdit"></v-look-item>
+</div>  
+</template>
+<script>
+// component
+import vLookItem from "./lookitem"; //查看item弹窗
+import vObjType from '@/components/alarm/common/ObjType' //对象类型
+// api
+import sopApi from "@/api/fm/sop"; //api
+import alarmApi from "@/api/alarm/alarm"; //sop通用api
+//tools
+import utils from '@/components/alarm/common/utils'
+//vuex
+import { mapGetters } from 'vuex'
+export default {
+    name: "group-sop-list",
+    data() {
+        return {
+            lookVisibleFlag: false, //查看弹窗的flag
+            itemInfoData: {}, //单条数据
+            projectValue: null, //项目绑定的value
+            searchValue: null, //搜索框中的value绑定值
+            searchLikeValue: null, //搜索框的模糊查询传值
+            priorityArr:[{ //优先级的下拉数组
+                label: "全部",
+                value: null
+            }], 
+            priorityValue: null , //优先级的value值
+            problemArr: [{ //问题类型的下拉数组
+                label: "全部",
+                value: null
+            }],
+            problemValue: null, //问题类型的value值
+            endCascadeValue: null, //级联框的最后一级的标识code
+            startCascadeValue: null, //级联框的最后一级的标识code
+            checked: false, //是否尚未配置集团SOP
+            tableData: [],
+            currentPage: 1, //当前的页数
+            currentSize: 10, //当前的Size
+            total:0, //总页数
+            sopObj: {}, //缓存sop的数据 {sopid:{}}
+        }
+    },
+    computed: {
+        ...mapGetters('alarm', ['spaceCodeObj', 'spaceNameObj'])
+    },
+    components: {
+        vLookItem,
+        vObjType
+    },
+    methods: {        
+        // 查看
+        getLook(row) {
+            this.lookVisibleFlag = !this.lookVisibleFlag;
+            this.itemInfoData = row;
+            this.itemInfoData.projectId = this.projectValue;
+        },
+        // 编辑
+        edit(row) {
+            row.projectId = this.projectValue;
+            this.$emit("to-edit", row);
+        },
+        // 查看页面去编辑页面
+        lookToEdit(row) {
+            this.$emit("to-edit", row);
+        },
+        // 去配置
+        toConfig(row) {
+            row.projectId = this.projectValue;
+            this.$emit("to-edit", row);
+        },
+        // 项目切换
+        projectedSelected(val){
+            this.projectValue = val
+            if(val){
+                this.projectHandle()
+            }
+        },
+        projectHandle() {
+            this.currentPage = 1;
+            this.searchValue = null;
+            this.priorityValue = null;
+            this.problemValue = null;
+            this.objTypeSelectArr = [null];
+            this.endCascadeValue =null;
+            this.checked = false;
+            this.cacheSopData();
+        },
+        // 对象类切换
+        objTypeChange(val) {
+            let start = null;
+            let end = null;
+            if(val.length){
+                start = val[0];
+                if(val[0] == 'space' ){
+                    if(val.length > 1) {
+                        // end = val[val.length - 1 ]
+                        let p = utils.spaceSonCode(val[val.length - 1 ], this.spaceCodeObj);
+                        end = p;
+                    } 
+                }
+                if(val[0] == 'system' || val[0] == 'facility') {
+                    if(val.length > 1) {
+                        end = [val[val.length - 1]]
+                    }
+                }
+            }
+            this.startCascadeValue = start;
+            this.endCascadeValue = end;
+            this.getListData()
+        },
+        // 查询
+        getSearch() {
+            if(this.searchValue) {
+                this.searchLikeValue = {
+                    $like: `%${this.searchValue}%`
+                }
+            } else {
+                this.searchLikeValue = null;
+            }
+            this.currentPage = 1;
+            this.getListData()
+        },
+        // 优先级下拉事件
+        priorityHandle() {
+            this.currentPage = 1;
+            this.getListData();
+        },
+        // 问题类型下拉事件
+        problemHandle() {
+            this.currentPage = 1;
+            this.getListData();
+        },
+        // 是否配置Sop事件
+        isSopHandle(val) {
+            this.currentPage = 1;
+            this.getListData();
+        },
+        // 分页Size处理函数
+        handleSizeChange(size) {
+            this.currentPage = 1;
+            this.currentSize = size;
+            this.getListData();
+        },
+        // 分页page处理函数
+        handleCurrentChange(page) {
+            this.currentPage = page;
+            this.getListData();
+        },
+        // 获取list的数据
+        async getListData() {
+            this.tableData = [];
+            let params = {
+                criteria: {
+                    id: null,                    //选填,通用问题id
+                    serialId: this.searchLikeValue,        //选填,编号
+                    name: this.searchLikeValue,         //选填,问题名称
+                    type: this.problemValue || null,              //选填,问题类型[电器,建筑,家具,其他]
+                    objType: this.startCascadeValue,        //选填,对象类型
+                    category: this.endCascadeValue ? {"$in":this.endCascadeValue } : null,
+                    priority: this.priorityValue || null,            //选填,优先级别[S,A,B,C,D]
+                    hasRule: null,               //选填,是否配置抢单规则,1已配置,0未配置
+                    hasSop: this.checked ? 0 : null,                 //选填,是否已配置sop,1已配置,0未配置
+                    projectId: this.projectValue  //选填,项目id
+                    
+                },
+                page: this.currentPage,                       //页码,从1开始
+                size: this.currentSize
+            };   
+            let {result, count, content} = await sopApi.getListData(params);
+            if(result === "success" && content && content.length) {
+                this.total = count;
+                let arr = content.map((ele, index) => {
+                    let objTypeName = alarmApi.getObjTypeNameFromCode(ele.objType, ele.category, this.spaceNameObj);       
+                    let  sopLinkName = "";
+                    
+                    if(ele.sopList && ele.sopList.length) {                        
+                        ele.sopList.forEach((sopItem, index) => {
+                            if ( this.sopObj[sopItem.sopId] ) {
+                                sopItem.sopName = this.sopObj[sopItem.sopId].sopName;
+                                sopLinkName += sopItem.sopName + (ele.sopList.length-1 == index ? "" : "、");
+                            } else {
+                                sopLinkName = "不存在";
+                            }                     
+                        })
+                    }                            
+                    return {
+                        id: ele.id,
+                        serialId: ele.serialId,
+                        type: ele.type,
+                        objType: objTypeName.name,
+                        priority: ele.priority,
+                        name: ele.name,
+                        remark: ele.remark, 
+                        sopLinkName: sopLinkName,
+                        sopList: ele.sopList || [],
+                    }
+                })
+                this.tableData = arr;
+            }
+        },
+        // 缓存sop的数据
+        async cacheSopData() {
+            // 获取sop的数组,用于列表展示name【id 去请求 name】
+            let {result, content} = await api.getSopList({projectId:this.projectValue});
+            if(result === "success" && content && content.length) {
+                content.forEach((item, index) => {
+                    this.sopObj[item.sopId] = item;
+                })
+                // 获取list数据
+                this.getListData();
+            }            
+        },
+        // 初始化数据
+        async initData() {
+            //获取优先级数组
+            let priorityArr = await sopApi.getPriorityArr();
+            this.priorityArr.push(...priorityArr);
+            // 获取问题类型
+            let problemArr = await sopApi.getProblemArr();
+            this.problemArr.push(...problemArr);
+            // // 获取对象类
+            let {devArr, sysArr} = await alarmApi.getObjectType();
+            this.cacheSopData();            
+        }    },
+    created() {
+        //判读是否存在
+        if(!this.spaceCodeObj || !this.spaceNameObj){
+             this.$store.commit("alarm/ADD_INDEX")
+        }
+        this.initData();
+    }
+}
+</script>
+<style lang='less' scoped>
+.line {
+    background-color: #ccc;
+    height: 1px;
+    border: none;
+    margin: 10px 0
+}
+.condition-box {
+    display: flex;
+    p {
+        font-size: 14px;
+        color: #5e6d82;
+        margin-right: 30px;
+    };
+    .check-box {
+        padding-top: 10px; 
+    }
+} 
+.table-box {
+    margin-top: 10px;
+    .config-btn {
+        color: red
+    }
+}
+.page-box {
+    margin-top: 10px;
+    text-align: center
+}
+</style>

+ 90 - 0
src/views/fm/projectsop/lookitem.vue

@@ -0,0 +1,90 @@
+/**
+@author:fugy
+@date:2018.10.24
+@info:项目sop配置列表的查看详情
+ */
+<template>
+<el-dialog
+title="报警条目详情"
+:visible.sync="dialogVisible"
+width="50%"
+center>
+    <div class="item-info-box">
+        <div class="item-info">
+            <p><span>问题名称 : </span><span>{{itemInfoData.name}}</span></p>
+            <p><span>问题编号 : </span><span>{{itemInfoData.serialId}}</span></p>
+            <p><span>问题类型 : </span><span>{{itemInfoData.type}}</span></p>
+            <p><span>优先级 : </span><span>{{itemInfoData.priority}}</span></p>
+            <!-- <p><span>适用建筑功能类型 : </span><span>{{"12312313"}}</span></p> -->
+            <p><span>问题详述 : </span><span>{{itemInfoData.remark || "---"}}</span></p>
+            <p><span class="link-sop-tit">关联的项目SOP : </span><span class="link-sop-name">{{itemInfoData.sopLinkName}}</span></p>
+        </div>        
+        <div class="btn-box"> 
+            <el-button class="edit-btn" type="primary" @click="editHandle">编辑</el-button>
+        </div>
+    </div>  
+</el-dialog>
+</template>
+<script>
+    export default {
+        name: "sop-look-item",
+        data() {
+            return {
+                dialogVisible: false,
+            }
+        },
+        props:{
+            lookVisibleFlag: {
+                type: Boolean,
+                required: true
+            },
+            itemInfoData: {
+                type: Object,
+                required: true
+            }
+        }, 
+        methods: {
+            // 编辑
+            editHandle() {
+                this.dialogVisible = false;
+                this.$emit("look-to-edit", this.itemInfoData);
+            },
+        },
+        watch: {
+            lookVisibleFlag:function(){
+                this.dialogVisible = true;
+            },
+        }
+    }
+</script>
+<style lang='less' scoped>
+.item-info-box{
+    .item-info{
+        padding-left:15%;
+        p{
+            padding: 10px 0;
+            overflow: hidden;
+            span{
+                float: left;
+            }
+            span:nth-of-type(1){
+                margin-right: 20px;
+            }
+            .link-sop-tit{
+                width: 108px;
+            }
+            .link-sop-name{
+                width: 300px;
+            }
+        }
+    }
+    .btn-box{
+        margin-top:20px;
+        text-align: center;
+        .edit-btn{
+            margin-right: 50px;
+        }
+    }
+    
+}
+</style>

+ 143 - 0
src/views/fm/projectsop/selectsop.vue

@@ -0,0 +1,143 @@
+/**
+@author:fugy
+@date:2018.10.24
+@info:项目sop配置列表的查看详情
+ */
+<template>
+<el-dialog
+title="选择SOP"
+:visible.sync="dialogVisible"
+width="50%"
+center>
+    <div class="select-sop-box">
+        <!-- top搜索框 -->
+        <div class="top">
+            <el-input
+            style="width: 400px;"
+            placeholder="请先输入SOP名称进行查询"
+            v-model.trim="searchValue"
+            clearable>
+            </el-input>
+            <el-button type="primary" @click="getSearch">查询</el-button>
+        </div>
+        <div class="table-box">
+            <el-table
+            :data="selectSopData"
+            border
+            style="width: 100%">
+                <el-table-column
+                prop="sopName"
+                label="SOP名称"
+                header-align="center">
+                </el-table-column>              
+                <el-table-column
+                :show-header="false"
+                label="选择"
+                width="50"
+                header-align="center">
+                    <template slot-scope="scope">
+                        <el-checkbox v-model="scope.row.checked"></el-checkbox>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </div>
+        <div class="btn-box">
+            <el-button size="medium" @click="cancel">取消</el-button>
+            <el-button type="primary" size="medium" class="save-btn" @click="save">保存</el-button>
+        </div>
+    </div>
+</el-dialog>
+</template>
+<script>
+import api from "@/api/fm/sop";
+
+export default {
+    name: "sop-look-item",
+    data() {
+        return {
+            dialogVisible: false,
+            searchValue: null, //查询search
+            selectSopData: [], //sop数组
+            
+        }
+    },
+    props:["selectSopVisibleFlag", "checkedSopArr","projectId"], 
+    methods: {
+        // 获取sopList数据
+        async getSopList() {
+            this.selectSopData = [];
+            let params = {
+                sopName: this.searchValue || null,
+                projectId: this.projectId
+            };
+            let {result, content} = await api.getSopList(params);
+            if(result === "success" && content && content.length) {
+                this.handleData(content);
+            }
+        },
+        handleData(arr) {
+            arr.forEach((ele, index) => {
+                ele.checked = false;
+            })
+            if(this.checkedSopArr.length) {
+                arr.forEach((item, index) => {
+                    this.checkedSopArr.forEach((ele, ind) => {
+                        if(item.sopId == ele.sopId) {
+                            item.checked = true;
+                        }
+                    })
+                })
+            } 
+            this.selectSopData = arr;
+        },
+        // 查询 
+        getSearch() {
+            this.getSopList();
+        },
+        // 取消
+        cancel() {
+            this.dialogVisible = false;
+        },
+        // 保存
+        save() {
+            let arr = this.selectSopData.filter((ele, index) => {
+                return ele.checked == true
+            })
+            if(arr.length) {
+                this.$emit("sop-checked", arr);
+                this.dialogVisible = false;
+            } else {
+                this.$message({
+                    message: '请选择SOP',
+                    type: 'warning'
+                });
+            }
+        }
+    },
+    watch: {
+        selectSopVisibleFlag:function(){
+            this.dialogVisible = true;
+            this.searchValue = null; //置空搜索项
+            this.selectSopData = [];
+            this.getSopList();
+        },
+    }
+}
+</script>
+<style lang='less' scoped>
+.select-sop-box {
+    .top{
+        text-align: center;
+    }
+    .table-box {
+        margin-top: 10px;
+        max-height: 450px;
+        overflow-y: auto;
+    }
+    .btn-box {
+        margin-top: 10px;
+        text-align: center;
+        .save-btn{margin-left: 50px;}
+    }
+}
+</style>