Compare commits
12 Commits
6c7b99ec50
...
d503e64098
| Author | SHA1 | Date | |
|---|---|---|---|
| d503e64098 | |||
| e7b0b54f01 | |||
| 5d76471571 | |||
| d03efb8d6f | |||
| 748464b44a | |||
| 4a0962b117 | |||
| ff8dd472de | |||
| b331d17032 | |||
| 39e239a886 | |||
| 76ae5832c0 | |||
| 3c9ed824d3 | |||
| 8ef37c5a96 |
@ -9,7 +9,7 @@ VITE_APP_BASE_API = 'http://192.168.110.119:8899'
|
|||||||
|
|
||||||
# 无人机接口地址
|
# 无人机接口地址
|
||||||
|
|
||||||
VITE_APP_BASE_DRONE_API = 'http://192.168.110.8:9136'
|
VITE_APP_BASE_DRONE_API = 'http://58.17.134.85:9512'
|
||||||
|
|
||||||
# 应用访问路径 例如使用前缀 /admin/
|
# 应用访问路径 例如使用前缀 /admin/
|
||||||
VITE_APP_CONTEXT_PATH = '/'
|
VITE_APP_CONTEXT_PATH = '/'
|
||||||
|
|||||||
@ -14,7 +14,7 @@ VITE_APP_MONITOR_ADMIN = '/admin/applications'
|
|||||||
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
|
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
|
||||||
|
|
||||||
# 生产环境
|
# 生产环境
|
||||||
VITE_APP_BASE_API = 'http://192.168.110.2:8899'
|
VITE_APP_BASE_API = 'http://58.17.134.85:8899'
|
||||||
|
|
||||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||||
VITE_BUILD_COMPRESS = gzip
|
VITE_BUILD_COMPRESS = gzip
|
||||||
|
|||||||
@ -212,6 +212,9 @@
|
|||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
src="http://58.17.134.85:7363/changxieoffice/web-apps/apps/api/documents/api.js"></script>
|
src="http://58.17.134.85:7363/changxieoffice/web-apps/apps/api/documents/api.js"></script>
|
||||||
<script src="/js/html-docx.js"></script>
|
<script src="/js/html-docx.js"></script>
|
||||||
|
<script src="/webrtc/adapter-7.4.0.min.js"></script>
|
||||||
|
<script src="/webrtc/jquery-1.12.2.min.js"></script>
|
||||||
|
<script src="/webrtc/srs.sdk.js"></script>
|
||||||
|
|
||||||
<script src="./src/assets/sdk/YJEarth.min.js"></script>
|
<script src="./src/assets/sdk/YJEarth.min.js"></script>
|
||||||
<script src="./src/utils/reconnecting-websocket.js"></script>
|
<script src="./src/utils/reconnecting-websocket.js"></script>
|
||||||
|
|||||||
BIN
public/webrtc/AdobeFlashPlayerInstall.swf
Normal file
BIN
public/webrtc/AdobeFlashPlayerInstall.swf
Normal file
Binary file not shown.
5551
public/webrtc/adapter-7.4.0.js
Normal file
5551
public/webrtc/adapter-7.4.0.js
Normal file
File diff suppressed because it is too large
Load Diff
1
public/webrtc/adapter-7.4.0.min.js
vendored
Normal file
1
public/webrtc/adapter-7.4.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
public/webrtc/bootstrap.min.js
vendored
Normal file
6
public/webrtc/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
9
public/webrtc/css/bootstrap.min.css
vendored
Normal file
9
public/webrtc/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
19
public/webrtc/dash-v4.5.1.all.min.js
vendored
Normal file
19
public/webrtc/dash-v4.5.1.all.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/webrtc/dash.all.min.js.map
Normal file
1
public/webrtc/dash.all.min.js.map
Normal file
File diff suppressed because one or more lines are too long
2
public/webrtc/hls-0.14.17.min.js
vendored
Normal file
2
public/webrtc/hls-0.14.17.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/webrtc/hls.min.js.map
Normal file
1
public/webrtc/hls.min.js.map
Normal file
File diff suppressed because one or more lines are too long
5
public/webrtc/jquery-1.12.2.min.js
vendored
Normal file
5
public/webrtc/jquery-1.12.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/webrtc/jquery-1.12.2.min.map
Normal file
1
public/webrtc/jquery-1.12.2.min.map
Normal file
File diff suppressed because one or more lines are too long
486
public/webrtc/json2.js
Normal file
486
public/webrtc/json2.js
Normal file
@ -0,0 +1,486 @@
|
|||||||
|
/*
|
||||||
|
json2.js
|
||||||
|
2013-05-26
|
||||||
|
|
||||||
|
Public Domain.
|
||||||
|
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
See http://www.JSON.org/js.html
|
||||||
|
|
||||||
|
|
||||||
|
This code should be minified before deployment.
|
||||||
|
See http://javascript.crockford.com/jsmin.html
|
||||||
|
|
||||||
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||||
|
NOT CONTROL.
|
||||||
|
|
||||||
|
|
||||||
|
This file creates a global JSON object containing two methods: stringify
|
||||||
|
and parse.
|
||||||
|
|
||||||
|
JSON.stringify(value, replacer, space)
|
||||||
|
value any JavaScript value, usually an object or array.
|
||||||
|
|
||||||
|
replacer an optional parameter that determines how object
|
||||||
|
values are stringified for objects. It can be a
|
||||||
|
function or an array of strings.
|
||||||
|
|
||||||
|
space an optional parameter that specifies the indentation
|
||||||
|
of nested structures. If it is omitted, the text will
|
||||||
|
be packed without extra whitespace. If it is a number,
|
||||||
|
it will specify the number of spaces to indent at each
|
||||||
|
level. If it is a string (such as '\t' or ' '),
|
||||||
|
it contains the characters used to indent at each level.
|
||||||
|
|
||||||
|
This method produces a JSON text from a JavaScript value.
|
||||||
|
|
||||||
|
When an object value is found, if the object contains a toJSON
|
||||||
|
method, its toJSON method will be called and the result will be
|
||||||
|
stringified. A toJSON method does not serialize: it returns the
|
||||||
|
value represented by the name/value pair that should be serialized,
|
||||||
|
or undefined if nothing should be serialized. The toJSON method
|
||||||
|
will be passed the key associated with the value, and this will be
|
||||||
|
bound to the value
|
||||||
|
|
||||||
|
For example, this would serialize Dates as ISO strings.
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function (key) {
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z';
|
||||||
|
};
|
||||||
|
|
||||||
|
You can provide an optional replacer method. It will be passed the
|
||||||
|
key and value of each member, with this bound to the containing
|
||||||
|
object. The value that is returned from your method will be
|
||||||
|
serialized. If your method returns undefined, then the member will
|
||||||
|
be excluded from the serialization.
|
||||||
|
|
||||||
|
If the replacer parameter is an array of strings, then it will be
|
||||||
|
used to select the members to be serialized. It filters the results
|
||||||
|
such that only members with keys listed in the replacer array are
|
||||||
|
stringified.
|
||||||
|
|
||||||
|
Values that do not have JSON representations, such as undefined or
|
||||||
|
functions, will not be serialized. Such values in objects will be
|
||||||
|
dropped; in arrays they will be replaced with null. You can use
|
||||||
|
a replacer function to replace those with JSON values.
|
||||||
|
JSON.stringify(undefined) returns undefined.
|
||||||
|
|
||||||
|
The optional space parameter produces a stringification of the
|
||||||
|
value that is filled with line breaks and indentation to make it
|
||||||
|
easier to read.
|
||||||
|
|
||||||
|
If the space parameter is a non-empty string, then that string will
|
||||||
|
be used for indentation. If the space parameter is a number, then
|
||||||
|
the indentation will be that many spaces.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||||
|
// text is '["e",{"pluribus":"unum"}]'
|
||||||
|
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||||
|
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||||
|
|
||||||
|
text = JSON.stringify([new Date()], function (key, value) {
|
||||||
|
return this[key] instanceof Date ?
|
||||||
|
'Date(' + this[key] + ')' : value;
|
||||||
|
});
|
||||||
|
// text is '["Date(---current time---)"]'
|
||||||
|
|
||||||
|
|
||||||
|
JSON.parse(text, reviver)
|
||||||
|
This method parses a JSON text to produce an object or array.
|
||||||
|
It can throw a SyntaxError exception.
|
||||||
|
|
||||||
|
The optional reviver parameter is a function that can filter and
|
||||||
|
transform the results. It receives each of the keys and values,
|
||||||
|
and its return value is used instead of the original value.
|
||||||
|
If it returns what it received, then the structure is not modified.
|
||||||
|
If it returns undefined then the member is deleted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
// Parse the text. Values that look like ISO date strings will
|
||||||
|
// be converted to Date objects.
|
||||||
|
|
||||||
|
myData = JSON.parse(text, function (key, value) {
|
||||||
|
var a;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
a =
|
||||||
|
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||||
|
if (a) {
|
||||||
|
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||||
|
+a[5], +a[6]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||||
|
var d;
|
||||||
|
if (typeof value === 'string' &&
|
||||||
|
value.slice(0, 5) === 'Date(' &&
|
||||||
|
value.slice(-1) === ')') {
|
||||||
|
d = new Date(value.slice(5, -1));
|
||||||
|
if (d) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
This is a reference implementation. You are free to copy, modify, or
|
||||||
|
redistribute.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jslint evil: true, regexp: true */
|
||||||
|
|
||||||
|
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||||
|
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||||
|
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||||
|
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||||
|
test, toJSON, toString, valueOf
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Create a JSON object only if one does not already exist. We create the
|
||||||
|
// methods in a closure to avoid creating global variables.
|
||||||
|
|
||||||
|
if (typeof JSON !== 'object') {
|
||||||
|
JSON = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof Date.prototype.toJSON !== 'function') {
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function () {
|
||||||
|
|
||||||
|
return isFinite(this.valueOf())
|
||||||
|
? this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z'
|
||||||
|
: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.toJSON =
|
||||||
|
Number.prototype.toJSON =
|
||||||
|
Boolean.prototype.toJSON = function () {
|
||||||
|
return this.valueOf();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
gap,
|
||||||
|
indent,
|
||||||
|
meta = { // table of character substitutions
|
||||||
|
'\b': '\\b',
|
||||||
|
'\t': '\\t',
|
||||||
|
'\n': '\\n',
|
||||||
|
'\f': '\\f',
|
||||||
|
'\r': '\\r',
|
||||||
|
'"' : '\\"',
|
||||||
|
'\\': '\\\\'
|
||||||
|
},
|
||||||
|
rep;
|
||||||
|
|
||||||
|
|
||||||
|
function quote(string) {
|
||||||
|
|
||||||
|
// If the string contains no control characters, no quote characters, and no
|
||||||
|
// backslash characters, then we can safely slap some quotes around it.
|
||||||
|
// Otherwise we must also replace the offending characters with safe escape
|
||||||
|
// sequences.
|
||||||
|
|
||||||
|
escapable.lastIndex = 0;
|
||||||
|
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
||||||
|
var c = meta[a];
|
||||||
|
return typeof c === 'string'
|
||||||
|
? c
|
||||||
|
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
}) + '"' : '"' + string + '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function str(key, holder) {
|
||||||
|
|
||||||
|
// Produce a string from holder[key].
|
||||||
|
|
||||||
|
var i, // The loop counter.
|
||||||
|
k, // The member key.
|
||||||
|
v, // The member value.
|
||||||
|
length,
|
||||||
|
mind = gap,
|
||||||
|
partial,
|
||||||
|
value = holder[key];
|
||||||
|
|
||||||
|
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||||
|
|
||||||
|
if (value && typeof value === 'object' &&
|
||||||
|
typeof value.toJSON === 'function') {
|
||||||
|
value = value.toJSON(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we were called with a replacer function, then call the replacer to
|
||||||
|
// obtain a replacement value.
|
||||||
|
|
||||||
|
if (typeof rep === 'function') {
|
||||||
|
value = rep.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// What happens next depends on the value's type.
|
||||||
|
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'string':
|
||||||
|
return quote(value);
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
|
||||||
|
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||||
|
|
||||||
|
return isFinite(value) ? String(value) : 'null';
|
||||||
|
|
||||||
|
case 'boolean':
|
||||||
|
case 'null':
|
||||||
|
|
||||||
|
// If the value is a boolean or null, convert it to a string. Note:
|
||||||
|
// typeof null does not produce 'null'. The case is included here in
|
||||||
|
// the remote chance that this gets fixed someday.
|
||||||
|
|
||||||
|
return String(value);
|
||||||
|
|
||||||
|
// If the type is 'object', we might be dealing with an object or an array or
|
||||||
|
// null.
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
|
||||||
|
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||||
|
// so watch out for that case.
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an array to hold the partial results of stringifying this object value.
|
||||||
|
|
||||||
|
gap += indent;
|
||||||
|
partial = [];
|
||||||
|
|
||||||
|
// Is the value an array?
|
||||||
|
|
||||||
|
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||||
|
|
||||||
|
// The value is an array. Stringify every element. Use null as a placeholder
|
||||||
|
// for non-JSON values.
|
||||||
|
|
||||||
|
length = value.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
partial[i] = str(i, value) || 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the elements together, separated with commas, and wrap them in
|
||||||
|
// brackets.
|
||||||
|
|
||||||
|
v = partial.length === 0
|
||||||
|
? '[]'
|
||||||
|
: gap
|
||||||
|
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
|
||||||
|
: '[' + partial.join(',') + ']';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the replacer is an array, use it to select the members to be stringified.
|
||||||
|
|
||||||
|
if (rep && typeof rep === 'object') {
|
||||||
|
length = rep.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
if (typeof rep[i] === 'string') {
|
||||||
|
k = rep[i];
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Otherwise, iterate through all of the keys in the object.
|
||||||
|
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the member texts together, separated with commas,
|
||||||
|
// and wrap them in braces.
|
||||||
|
|
||||||
|
v = partial.length === 0
|
||||||
|
? '{}'
|
||||||
|
: gap
|
||||||
|
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
|
||||||
|
: '{' + partial.join(',') + '}';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a stringify method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.stringify !== 'function') {
|
||||||
|
JSON.stringify = function (value, replacer, space) {
|
||||||
|
|
||||||
|
// The stringify method takes a value and an optional replacer, and an optional
|
||||||
|
// space parameter, and returns a JSON text. The replacer can be a function
|
||||||
|
// that can replace values, or an array of strings that will select the keys.
|
||||||
|
// A default replacer method can be provided. Use of the space parameter can
|
||||||
|
// produce text that is more easily readable.
|
||||||
|
|
||||||
|
var i;
|
||||||
|
gap = '';
|
||||||
|
indent = '';
|
||||||
|
|
||||||
|
// If the space parameter is a number, make an indent string containing that
|
||||||
|
// many spaces.
|
||||||
|
|
||||||
|
if (typeof space === 'number') {
|
||||||
|
for (i = 0; i < space; i += 1) {
|
||||||
|
indent += ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the space parameter is a string, it will be used as the indent string.
|
||||||
|
|
||||||
|
} else if (typeof space === 'string') {
|
||||||
|
indent = space;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a replacer, it must be a function or an array.
|
||||||
|
// Otherwise, throw an error.
|
||||||
|
|
||||||
|
rep = replacer;
|
||||||
|
if (replacer && typeof replacer !== 'function' &&
|
||||||
|
(typeof replacer !== 'object' ||
|
||||||
|
typeof replacer.length !== 'number')) {
|
||||||
|
throw new Error('JSON.stringify');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a fake root object containing our value under the key of ''.
|
||||||
|
// Return the result of stringifying the value.
|
||||||
|
|
||||||
|
return str('', {'': value});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a parse method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.parse !== 'function') {
|
||||||
|
JSON.parse = function (text, reviver) {
|
||||||
|
|
||||||
|
// The parse method takes a text and an optional reviver function, and returns
|
||||||
|
// a JavaScript value if the text is a valid JSON text.
|
||||||
|
|
||||||
|
var j;
|
||||||
|
|
||||||
|
function walk(holder, key) {
|
||||||
|
|
||||||
|
// The walk method is used to recursively walk the resulting structure so
|
||||||
|
// that modifications can be made.
|
||||||
|
|
||||||
|
var k, v, value = holder[key];
|
||||||
|
if (value && typeof value === 'object') {
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||||
|
v = walk(value, k);
|
||||||
|
if (v !== undefined) {
|
||||||
|
value[k] = v;
|
||||||
|
} else {
|
||||||
|
delete value[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reviver.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Parsing happens in four stages. In the first stage, we replace certain
|
||||||
|
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||||
|
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||||
|
|
||||||
|
text = String(text);
|
||||||
|
cx.lastIndex = 0;
|
||||||
|
if (cx.test(text)) {
|
||||||
|
text = text.replace(cx, function (a) {
|
||||||
|
return '\\u' +
|
||||||
|
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the second stage, we run the text against regular expressions that look
|
||||||
|
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||||
|
// because they can cause invocation, and '=' because it can cause mutation.
|
||||||
|
// But just to be safe, we want to reject all unexpected forms.
|
||||||
|
|
||||||
|
// We split the second stage into 4 regexp operations in order to work around
|
||||||
|
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||||
|
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||||
|
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||||
|
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||||
|
// we look to see that the remaining characters are only whitespace or ']' or
|
||||||
|
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||||
|
|
||||||
|
if (/^[\],:{}\s]*$/
|
||||||
|
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
|
||||||
|
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
|
||||||
|
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||||
|
|
||||||
|
// In the third stage we use the eval function to compile the text into a
|
||||||
|
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||||
|
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||||
|
// in parens to eliminate the ambiguity.
|
||||||
|
|
||||||
|
j = eval('(' + text + ')');
|
||||||
|
|
||||||
|
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||||
|
// each name/value pair to a reviver function for possible transformation.
|
||||||
|
|
||||||
|
return typeof reviver === 'function'
|
||||||
|
? walk({'': j}, '')
|
||||||
|
: j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||||
|
|
||||||
|
throw new SyntaxError('JSON.parse');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}());
|
||||||
9
public/webrtc/mpegts-1.7.2.min.js
vendored
Normal file
9
public/webrtc/mpegts-1.7.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/webrtc/mpegts.js.map
Normal file
1
public/webrtc/mpegts.js.map
Normal file
File diff suppressed because one or more lines are too long
37
public/webrtc/srs.log.js
Normal file
37
public/webrtc/srs.log.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* log specified, there must be a log element as:
|
||||||
|
<!-- for the log -->
|
||||||
|
<div class="alert alert-info fade in" id="txt_log">
|
||||||
|
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||||
|
<strong><span id="txt_log_title">标题:</span></strong>
|
||||||
|
<span id="txt_log_msg">日志内容</span>
|
||||||
|
</div>
|
||||||
|
*/
|
||||||
|
var srs_log_disabled = false;
|
||||||
|
function info(desc) {
|
||||||
|
if (srs_log_disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#txt_log").addClass("alert-info").removeClass("alert-error").removeClass("alert-warn");
|
||||||
|
$("#txt_log_title").text("Info:");
|
||||||
|
$("#txt_log_msg").html(desc);
|
||||||
|
}
|
||||||
|
function warn(code, desc) {
|
||||||
|
if (srs_log_disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#txt_log").removeClass("alert-info").removeClass("alert-error").addClass("alert-warn");
|
||||||
|
$("#txt_log_title").text("Warn:");
|
||||||
|
$("#txt_log_msg").html("code: " + code + ", " + desc);
|
||||||
|
}
|
||||||
|
function error(code, desc) {
|
||||||
|
if (srs_log_disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#txt_log").removeClass("alert-info").addClass("alert-error").removeClass("alert-warn");
|
||||||
|
$("#txt_log_title").text("Error:");
|
||||||
|
$("#txt_log_msg").html("code: " + code + ", " + desc);
|
||||||
|
}
|
||||||
182
public/webrtc/srs.page.js
Normal file
182
public/webrtc/srs.page.js
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
|
||||||
|
// to query the swf anti cache.
|
||||||
|
function srs_get_version_code() { return "1.33"; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* player specified size.
|
||||||
|
*/
|
||||||
|
function srs_get_player_modal() { return 740; }
|
||||||
|
function srs_get_player_width() { return srs_get_player_modal() - 30; }
|
||||||
|
function srs_get_player_height() { return srs_get_player_width() * 9 / 19; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update the navigator, add same query string.
|
||||||
|
*/
|
||||||
|
function update_nav() {
|
||||||
|
$("#nav_srs_player").attr("href", "srs_player.html" + window.location.search);
|
||||||
|
$("#nav_rtc_player").attr("href", "rtc_player.html" + window.location.search);
|
||||||
|
$("#nav_rtc_publisher").attr("href", "rtc_publisher.html" + window.location.search);
|
||||||
|
$("#nav_whip").attr("href", "whip.html" + window.location.search);
|
||||||
|
$("#nav_whep").attr("href", "whep.html" + window.location.search);
|
||||||
|
$("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search);
|
||||||
|
$("#nav_srs_chat").attr("href", "srs_chat.html" + window.location.search);
|
||||||
|
$("#nav_srs_bwt").attr("href", "srs_bwt.html" + window.location.search);
|
||||||
|
$("#nav_vlc").attr("href", "vlc.html" + window.location.search);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special extra params, such as auth_key.
|
||||||
|
function user_extra_params(query, params, rtc) {
|
||||||
|
var queries = params || [];
|
||||||
|
|
||||||
|
for (var key in query.user_query) {
|
||||||
|
if (key === 'app' || key === 'autostart' || key === 'dir'
|
||||||
|
|| key === 'filename' || key === 'host' || key === 'hostname'
|
||||||
|
|| key === 'http_port' || key === 'pathname' || key === 'port'
|
||||||
|
|| key === 'server' || key === 'stream' || key === 'buffer'
|
||||||
|
|| key === 'schema' || key === 'vhost' || key === 'api'
|
||||||
|
|| key === 'path'
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query[key]) {
|
||||||
|
queries.push(key + '=' + query[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return queries;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_default_port(schema, port) {
|
||||||
|
return (schema === 'http' && port === 80)
|
||||||
|
|| (schema === 'https' && port === 443)
|
||||||
|
|| (schema === 'webrtc' && port === 1985)
|
||||||
|
|| (schema === 'rtmp' && port === 1935);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@param server the ip of server. default to window.location.hostname
|
||||||
|
@param vhost the vhost of HTTP-FLV. default to window.location.hostname
|
||||||
|
@param port the port of HTTP-FLV. default to 1935
|
||||||
|
@param app the app of HTTP-FLV. default to live.
|
||||||
|
@param stream the stream of HTTP-FLV. default to livestream.flv
|
||||||
|
*/
|
||||||
|
function build_default_flv_url() {
|
||||||
|
var query = parse_query_string();
|
||||||
|
|
||||||
|
var schema = (!query.schema)? "http":query.schema;
|
||||||
|
var server = (!query.server)? window.location.hostname:query.server;
|
||||||
|
var port = (!query.port)? (schema==="http"? 8080:1935) : Number(query.port);
|
||||||
|
var vhost = (!query.vhost)? window.location.hostname:query.vhost;
|
||||||
|
var app = (!query.app)? "live":query.app;
|
||||||
|
var stream = (!query.stream)? "livestream.flv":query.stream;
|
||||||
|
|
||||||
|
var queries = [];
|
||||||
|
if (server !== vhost && vhost !== "__defaultVhost__") {
|
||||||
|
queries.push("vhost=" + vhost);
|
||||||
|
}
|
||||||
|
queries = user_extra_params(query, queries);
|
||||||
|
|
||||||
|
var uri = schema + "://" + server;
|
||||||
|
if (!is_default_port(schema, port)) {
|
||||||
|
uri += ":" + port;
|
||||||
|
}
|
||||||
|
uri += "/" + app + "/" + stream + "?" + queries.join('&');
|
||||||
|
while (uri.indexOf("?") === uri.length - 1) {
|
||||||
|
uri = uri.slice(0, uri.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_default_rtc_url(query) {
|
||||||
|
// The format for query string to overwrite configs of server.
|
||||||
|
console.log('?eip=x.x.x.x to overwrite candidate. 覆盖服务器candidate(外网IP)配置');
|
||||||
|
console.log('?api=x to overwrite WebRTC API(1985).');
|
||||||
|
console.log('?schema=http|https to overwrite WebRTC API protocol.');
|
||||||
|
|
||||||
|
var server = (!query.server)? window.location.hostname:query.server;
|
||||||
|
var vhost = (!query.vhost)? window.location.hostname:query.vhost;
|
||||||
|
var app = (!query.app)? "live":query.app;
|
||||||
|
var stream = (!query.stream)? "livestream":query.stream;
|
||||||
|
var api = query.api? ':'+query.api : '';
|
||||||
|
|
||||||
|
var queries = [];
|
||||||
|
if (server !== vhost && vhost !== "__defaultVhost__") {
|
||||||
|
queries.push("vhost=" + vhost);
|
||||||
|
}
|
||||||
|
if (query.schema && window.location.protocol !== query.schema + ':') {
|
||||||
|
queries.push('schema=' + query.schema);
|
||||||
|
}
|
||||||
|
queries = user_extra_params(query, queries, true);
|
||||||
|
|
||||||
|
var uri = "webrtc://" + server + api + "/" + app + "/" + stream + "?" + queries.join('&');
|
||||||
|
while (uri.lastIndexOf("?") === uri.length - 1) {
|
||||||
|
uri = uri.slice(0, uri.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
};
|
||||||
|
|
||||||
|
function build_default_whip_whep_url(query, apiPath) {
|
||||||
|
// The format for query string to overwrite configs of server.
|
||||||
|
console.log('?eip=x.x.x.x to overwrite candidate. 覆盖服务器candidate(外网IP)配置');
|
||||||
|
console.log('?api=x to overwrite WebRTC API(1985).');
|
||||||
|
console.log('?schema=http|https to overwrite WebRTC API protocol.');
|
||||||
|
console.log(`?path=xxx to overwrite default ${apiPath}`);
|
||||||
|
|
||||||
|
var server = (!query.server)? window.location.hostname:query.server;
|
||||||
|
var vhost = (!query.vhost)? window.location.hostname:query.vhost;
|
||||||
|
var app = (!query.app)? "live":query.app;
|
||||||
|
var stream = (!query.stream)? "livestream":query.stream;
|
||||||
|
var api = ':' + (query.api || (window.location.protocol === 'http:' ? '1985' : '1990'));
|
||||||
|
const realApiPath = query.path || apiPath;
|
||||||
|
|
||||||
|
var queries = [];
|
||||||
|
if (server !== vhost && vhost !== "__defaultVhost__") {
|
||||||
|
queries.push("vhost=" + vhost);
|
||||||
|
}
|
||||||
|
if (query.schema && window.location.protocol !== query.schema + ':') {
|
||||||
|
queries.push('schema=' + query.schema);
|
||||||
|
}
|
||||||
|
queries = user_extra_params(query, queries, true);
|
||||||
|
|
||||||
|
var uri = window.location.protocol + "//" + server + api + realApiPath + "?app=" + app + "&stream=" + stream + "&" + queries.join('&');
|
||||||
|
while (uri.lastIndexOf("?") === uri.length - 1) {
|
||||||
|
uri = uri.slice(0, uri.length - 1);
|
||||||
|
}
|
||||||
|
while (uri.lastIndexOf("&") === uri.length - 1) {
|
||||||
|
uri = uri.slice(0, uri.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initialize the page.
|
||||||
|
* @param flv_url the div id contains the flv stream url to play
|
||||||
|
* @param hls_url the div id contains the hls stream url to play
|
||||||
|
* @param modal_player the div id contains the modal player
|
||||||
|
*/
|
||||||
|
function srs_init_flv(flv_url, modal_player) {
|
||||||
|
update_nav();
|
||||||
|
if (flv_url) {
|
||||||
|
$(flv_url).val(build_default_flv_url());
|
||||||
|
}
|
||||||
|
if (modal_player) {
|
||||||
|
$(modal_player).width(srs_get_player_modal() + "px");
|
||||||
|
$(modal_player).css("margin-left", "-" + srs_get_player_modal() / 2 +"px");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function srs_init_rtc(id, query) {
|
||||||
|
update_nav();
|
||||||
|
$(id).val(build_default_rtc_url(query));
|
||||||
|
}
|
||||||
|
function srs_init_whip(id, query) {
|
||||||
|
update_nav();
|
||||||
|
$(id).val(build_default_whip_whep_url(query, '/rtc/v1/whip/'));
|
||||||
|
}
|
||||||
|
function srs_init_whep(id, query) {
|
||||||
|
update_nav();
|
||||||
|
$(id).val(build_default_whip_whep_url(query, '/rtc/v1/whep/'));
|
||||||
|
}
|
||||||
382
public/webrtc/srs.player.js
Normal file
382
public/webrtc/srs.player.js
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
/**
|
||||||
|
* the SrsPlayer object.
|
||||||
|
* @param container the html container id.
|
||||||
|
* @param width a float value specifies the width of player.
|
||||||
|
* @param height a float value specifies the height of player.
|
||||||
|
* @param private_object [optional] an object that used as private object,
|
||||||
|
* for example, the logic chat object which owner this player.
|
||||||
|
* Usage:
|
||||||
|
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||||
|
<script type="text/javascript" src="js/srs.player.js"></script>
|
||||||
|
<div id="player"></div>
|
||||||
|
var p = new SrsPlayer("player", 640, 480);
|
||||||
|
p.set_srs_player_url("srs_player.swf?v=1.0.0");
|
||||||
|
p.on_player_ready = function() {
|
||||||
|
p.set_bt(0.8);
|
||||||
|
p.set_mbt(1.2);
|
||||||
|
p.play("rtmp://ossrs.net/live/livestream");
|
||||||
|
};
|
||||||
|
p.on_player_metadata = function(metadata) {
|
||||||
|
console.log(metadata);
|
||||||
|
console.log(p.dump_log());
|
||||||
|
};
|
||||||
|
p.start();
|
||||||
|
*/
|
||||||
|
function SrsPlayer(container, width, height, private_object) {
|
||||||
|
if (!SrsPlayer.__id) {
|
||||||
|
SrsPlayer.__id = 100;
|
||||||
|
}
|
||||||
|
if (!SrsPlayer.__players) {
|
||||||
|
SrsPlayer.__players = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsPlayer.__players.push(this);
|
||||||
|
|
||||||
|
this.private_object = private_object;
|
||||||
|
this.container = container;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.id = SrsPlayer.__id++;
|
||||||
|
this.stream_url = null;
|
||||||
|
this.buffer_time = 0.3; // default to 0.3
|
||||||
|
this.max_buffer_time = this.buffer_time * 3; // default to 3 x bufferTime.
|
||||||
|
this.volume = 1.0; // default to 100%
|
||||||
|
this.callbackObj = null;
|
||||||
|
this.srs_player_url = "srs_player/release/srs_player.swf?_version="+srs_get_version_code();
|
||||||
|
|
||||||
|
// callback set the following values.
|
||||||
|
this.meatadata = {}; // for on_player_metadata
|
||||||
|
this.time = 0; // current stream time.
|
||||||
|
this.buffer_length = 0; // current stream buffer length.
|
||||||
|
this.kbps = 0; // current stream bitrate(video+audio) in kbps.
|
||||||
|
this.fps = 0; // current stream video fps.
|
||||||
|
this.rtime = 0; // flash relative time in ms.
|
||||||
|
|
||||||
|
this.__fluency = {
|
||||||
|
total_empty_count: 0,
|
||||||
|
total_empty_time: 0,
|
||||||
|
current_empty_time: 0
|
||||||
|
};
|
||||||
|
this.__fluency.on_stream_empty = function(time) {
|
||||||
|
this.total_empty_count++;
|
||||||
|
this.current_empty_time = time;
|
||||||
|
};
|
||||||
|
this.__fluency.on_stream_full = function(time) {
|
||||||
|
if (this.current_empty_time > 0) {
|
||||||
|
this.total_empty_time += time - this.current_empty_time;
|
||||||
|
this.current_empty_time = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.__fluency.calc = function(time) {
|
||||||
|
var den = this.total_empty_count * 4 + this.total_empty_time * 2 + time;
|
||||||
|
if (den > 0) {
|
||||||
|
return time * 100 / den;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* user can set some callback, then start the player.
|
||||||
|
* @param url the default url.
|
||||||
|
* callbacks:
|
||||||
|
* on_player_ready():int, when srs player ready, user can play().
|
||||||
|
* on_player_metadata(metadata:Object):int, when srs player get metadata.
|
||||||
|
* methods:
|
||||||
|
* set_bt(t:Number):void, set the buffer time in seconds.
|
||||||
|
* set_mbt(t:Number):void, set the max buffer time in seconds.
|
||||||
|
* dump_log():String, get all logs of player.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.start = function(url) {
|
||||||
|
if (url) {
|
||||||
|
this.stream_url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// embed the flash.
|
||||||
|
var flashvars = {};
|
||||||
|
flashvars.id = this.id;
|
||||||
|
flashvars.on_player_ready = "__srs_on_player_ready";
|
||||||
|
flashvars.on_player_metadata = "__srs_on_player_metadata";
|
||||||
|
flashvars.on_player_timer = "__srs_on_player_timer";
|
||||||
|
flashvars.on_player_empty = "__srs_on_player_empty";
|
||||||
|
flashvars.on_player_full = "__srs_on_player_full";
|
||||||
|
flashvars.on_player_status = "__srs_on_player_status";
|
||||||
|
|
||||||
|
var params = {};
|
||||||
|
params.wmode = "opaque";
|
||||||
|
params.allowFullScreen = "true";
|
||||||
|
params.allowScriptAccess = "always";
|
||||||
|
|
||||||
|
var attributes = {};
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
swfobject.embedSWF(
|
||||||
|
this.srs_player_url,
|
||||||
|
this.container,
|
||||||
|
this.width, this.height,
|
||||||
|
"11.1.0", "js/AdobeFlashPlayerInstall.swf",
|
||||||
|
flashvars, params, attributes,
|
||||||
|
function(callbackObj){
|
||||||
|
self.callbackObj = callbackObj;
|
||||||
|
if (!callbackObj.success) {
|
||||||
|
console.error('Initialize player failed:'); console.error(callbackObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* play the stream.
|
||||||
|
* @param stream_url the url of stream, rtmp or http.
|
||||||
|
* @param volume the volume, 0 is mute, 1 is 100%, 2 is 200%.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.play = function(url, volume) {
|
||||||
|
this.stop();
|
||||||
|
SrsPlayer.__players.push(this);
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
this.stream_url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// volume maybe 0, so never use if(volume) to check its value.
|
||||||
|
if (volume != null && volume != undefined) {
|
||||||
|
this.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time, this.max_buffer_time, this.volume);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* stop play stream.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.stop = function() {
|
||||||
|
this.callbackObj.ref.__stop();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* pause the play.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.pause = function() {
|
||||||
|
this.callbackObj.ref.__pause();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* resume the play.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.resume = function() {
|
||||||
|
this.callbackObj.ref.__resume();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* get the stream fluency, where 100 is 100%.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.fluency = function() {
|
||||||
|
return this.__fluency.calc(this.rtime);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* get the stream empty count.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.empty_count = function() {
|
||||||
|
return this.__fluency.total_empty_count;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* get all log data.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.dump_log = function() {
|
||||||
|
return this.callbackObj.ref.__dump_log();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* to set the DAR, for example, DAR=16:9 where num=16,den=9.
|
||||||
|
* @param num, for example, 16.
|
||||||
|
* use metadata width if 0.
|
||||||
|
* use user specified width if -1.
|
||||||
|
* @param den, for example, 9.
|
||||||
|
* use metadata height if 0.
|
||||||
|
* use user specified height if -1.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.set_dar = function(num, den) {
|
||||||
|
this.callbackObj.ref.__set_dar(num, den);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* set the fullscreen size data.
|
||||||
|
* @refer the refer fullscreen mode. it can be:
|
||||||
|
* video: use video orignal size.
|
||||||
|
* screen: use screen size to rescale video.
|
||||||
|
* @param percent, the rescale percent, where
|
||||||
|
* 100 means 100%.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.set_fs = function(refer, percent) {
|
||||||
|
this.callbackObj.ref.__set_fs(refer, percent);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* set the stream buffer time in seconds.
|
||||||
|
* @buffer_time the buffer time in seconds.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.set_bt = function(buffer_time) {
|
||||||
|
if (this.buffer_time == buffer_time) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buffer_time = buffer_time;
|
||||||
|
this.callbackObj.ref.__set_bt(buffer_time);
|
||||||
|
|
||||||
|
// reset the max buffer time to 3 x buffer_time.
|
||||||
|
this.set_mbt(buffer_time * 3);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* set the stream max buffer time in seconds.
|
||||||
|
* @param max_buffer_time the max buffer time in seconds.
|
||||||
|
* @remark this is the key feature for realtime communication by flash.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.set_mbt = function(max_buffer_time) {
|
||||||
|
// we must atleast set the max buffer time to 0.6s.
|
||||||
|
max_buffer_time = Math.max(0.6, max_buffer_time);
|
||||||
|
// max buffer time always greater than buffer time.
|
||||||
|
max_buffer_time = Math.max(this.buffer_time, max_buffer_time);
|
||||||
|
|
||||||
|
if (parseInt(this.max_buffer_time * 10) == parseInt(max_buffer_time * 10)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.max_buffer_time = max_buffer_time;
|
||||||
|
this.callbackObj.ref.__set_mbt(max_buffer_time);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* set the srs_player.swf url
|
||||||
|
* @param url, srs_player.swf's url.
|
||||||
|
* @param params, object.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.set_srs_player_url = function(url, params) {
|
||||||
|
var query_array = [],
|
||||||
|
query_string = "",
|
||||||
|
p;
|
||||||
|
params = params || {};
|
||||||
|
params._version = srs_get_version_code();
|
||||||
|
for (p in params) {
|
||||||
|
if (params.hasOwnProperty(p)) {
|
||||||
|
query_array.push(p + "=" + encodeURIComponent(params[p]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
query_string = query_array.join("&");
|
||||||
|
this.srs_player_url = url + "?" + query_string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* the callback when player is ready.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.on_player_ready = function() {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* the callback when player got metadata.
|
||||||
|
* @param metadata the metadata which player got.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.on_player_metadata = function(metadata) {
|
||||||
|
// ignore.
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* the callback when player timer event.
|
||||||
|
* @param time current stream time.
|
||||||
|
* @param buffer_length current buffer length.
|
||||||
|
* @param kbps current video plus audio bitrate in kbps.
|
||||||
|
* @param fps current video fps.
|
||||||
|
* @param rtime current relative time by flash.util.getTimer().
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.on_player_timer = function(time, buffer_length, kbps, fps, rtime) {
|
||||||
|
// ignore.
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* the callback when player got NetStream.Buffer.Empty
|
||||||
|
* @param time current relative time by flash.util.getTimer().
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.on_player_empty = function(time) {
|
||||||
|
// ignore.
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* the callback when player got NetStream.Buffer.Full
|
||||||
|
* @param time current relative time by flash.util.getTimer().
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.on_player_full = function(time) {
|
||||||
|
// ignore.
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* the callback when player status change.
|
||||||
|
* @param code the status code, "init", "connected", "play", "closed", "rejected", "failed".
|
||||||
|
* init => connected/rejected/failed
|
||||||
|
* connected => play/rejected => closed
|
||||||
|
* @param desc the description for the status.
|
||||||
|
*/
|
||||||
|
SrsPlayer.prototype.on_player_status = function(code, desc) {
|
||||||
|
// ignore.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helpers.
|
||||||
|
*/
|
||||||
|
function __srs_find_player(id) {
|
||||||
|
for (var i = 0; i < SrsPlayer.__players.length; i++) {
|
||||||
|
var player = SrsPlayer.__players[i];
|
||||||
|
|
||||||
|
if (player.id != id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("player not found. id=" + id);
|
||||||
|
}
|
||||||
|
function __srs_on_player_ready(id) {
|
||||||
|
var player = __srs_find_player(id);
|
||||||
|
player.on_player_ready();
|
||||||
|
}
|
||||||
|
function __srs_on_player_metadata(id, metadata) {
|
||||||
|
var player = __srs_find_player(id);
|
||||||
|
|
||||||
|
// user may override the on_player_metadata,
|
||||||
|
// so set the data before invoke it.
|
||||||
|
player.metadata = metadata;
|
||||||
|
|
||||||
|
player.on_player_metadata(metadata);
|
||||||
|
}
|
||||||
|
function __srs_on_player_timer(id, time, buffer_length, kbps, fps, rtime) {
|
||||||
|
var player = __srs_find_player(id);
|
||||||
|
|
||||||
|
buffer_length = Math.max(0, buffer_length);
|
||||||
|
buffer_length = Math.min(player.buffer_time, buffer_length);
|
||||||
|
|
||||||
|
time = Math.max(0, time);
|
||||||
|
|
||||||
|
// user may override the on_player_timer,
|
||||||
|
// so set the data before invoke it.
|
||||||
|
player.time = time;
|
||||||
|
player.buffer_length = buffer_length;
|
||||||
|
player.kbps = kbps;
|
||||||
|
player.fps = fps;
|
||||||
|
player.rtime = rtime;
|
||||||
|
|
||||||
|
player.on_player_timer(time, buffer_length, kbps, fps, rtime);
|
||||||
|
}
|
||||||
|
function __srs_on_player_empty(id, time) {
|
||||||
|
var player = __srs_find_player(id);
|
||||||
|
player.__fluency.on_stream_empty(time);
|
||||||
|
player.on_player_empty(time);
|
||||||
|
}
|
||||||
|
function __srs_on_player_full(id, time) {
|
||||||
|
var player = __srs_find_player(id);
|
||||||
|
player.__fluency.on_stream_full(time);
|
||||||
|
player.on_player_full(time);
|
||||||
|
}
|
||||||
|
function __srs_on_player_status(id, code, desc) {
|
||||||
|
var player = __srs_find_player(id);
|
||||||
|
player.on_player_status(code, desc);
|
||||||
|
|
||||||
|
if (code != "closed") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < SrsPlayer.__players.length; i++) {
|
||||||
|
var player = SrsPlayer.__players[i];
|
||||||
|
|
||||||
|
if (player.id != this.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsPlayer.__players.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
173
public/webrtc/srs.publisher.js
Normal file
173
public/webrtc/srs.publisher.js
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/**
|
||||||
|
* the SrsPublisher object.
|
||||||
|
* @param container the html container id.
|
||||||
|
* @param width a float value specifies the width of publisher.
|
||||||
|
* @param height a float value specifies the height of publisher.
|
||||||
|
* @param private_object [optional] an object that used as private object,
|
||||||
|
* for example, the logic chat object which owner this publisher.
|
||||||
|
*/
|
||||||
|
function SrsPublisher(container, width, height, private_object) {
|
||||||
|
if (!SrsPublisher.__id) {
|
||||||
|
SrsPublisher.__id = 100;
|
||||||
|
}
|
||||||
|
if (!SrsPublisher.__publishers) {
|
||||||
|
SrsPublisher.__publishers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsPublisher.__publishers.push(this);
|
||||||
|
|
||||||
|
this.private_object = private_object;
|
||||||
|
this.container = container;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.id = SrsPublisher.__id++;
|
||||||
|
this.callbackObj = null;
|
||||||
|
|
||||||
|
// set the values when publish.
|
||||||
|
this.url = null;
|
||||||
|
this.vcodec = {};
|
||||||
|
this.acodec = {};
|
||||||
|
|
||||||
|
// callback set the following values.
|
||||||
|
this.cameras = [];
|
||||||
|
this.microphones = [];
|
||||||
|
this.code = 0;
|
||||||
|
|
||||||
|
// error code defines.
|
||||||
|
this.errors = {
|
||||||
|
"100": "无法获取指定的摄像头。", //error_camera_get
|
||||||
|
"101": "无法获取指定的麦克风。", //error_microphone_get
|
||||||
|
"102": "摄像头为禁用状态,推流时请允许flash访问摄像头。", //error_camera_muted
|
||||||
|
"103": "服务器关闭了连接。", //error_connection_closed
|
||||||
|
"104": "服务器连接失败。", //error_connection_failed
|
||||||
|
"199": "未知错误。"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* user can set some callback, then start the publisher.
|
||||||
|
* callbacks:
|
||||||
|
* on_publisher_ready(cameras, microphones):int, when srs publisher ready, user can publish.
|
||||||
|
* on_publisher_error(code, desc):int, when srs publisher error, callback this method.
|
||||||
|
* on_publisher_warn(code, desc):int, when srs publisher warn, callback this method.
|
||||||
|
*/
|
||||||
|
SrsPublisher.prototype.start = function() {
|
||||||
|
// embed the flash.
|
||||||
|
var flashvars = {};
|
||||||
|
flashvars.id = this.id;
|
||||||
|
flashvars.width = this.width;
|
||||||
|
flashvars.height = this.height;
|
||||||
|
flashvars.on_publisher_ready = "__srs_on_publisher_ready";
|
||||||
|
flashvars.on_publisher_error = "__srs_on_publisher_error";
|
||||||
|
flashvars.on_publisher_warn = "__srs_on_publisher_warn";
|
||||||
|
|
||||||
|
var params = {};
|
||||||
|
params.wmode = "opaque";
|
||||||
|
params.allowFullScreen = "true";
|
||||||
|
params.allowScriptAccess = "always";
|
||||||
|
|
||||||
|
var attributes = {};
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
swfobject.embedSWF(
|
||||||
|
"srs_publisher/release/srs_publisher.swf?_version="+srs_get_version_code(),
|
||||||
|
this.container,
|
||||||
|
this.width, this.height,
|
||||||
|
"11.1.0", "js/AdobeFlashPlayerInstall.swf",
|
||||||
|
flashvars, params, attributes,
|
||||||
|
function(callbackObj){
|
||||||
|
self.callbackObj = callbackObj;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* publish stream to server.
|
||||||
|
* @param url a string indicates the rtmp url to publish.
|
||||||
|
* @param vcodec an object contains the video codec info.
|
||||||
|
* @param acodec an object contains the audio codec info.
|
||||||
|
*/
|
||||||
|
SrsPublisher.prototype.publish = function(url, vcodec, acodec) {
|
||||||
|
this.stop();
|
||||||
|
SrsPublisher.__publishers.push(this);
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
if (vcodec) {
|
||||||
|
this.vcodec = vcodec;
|
||||||
|
}
|
||||||
|
if (acodec) {
|
||||||
|
this.acodec = acodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.callbackObj.ref.__publish(this.url, this.width, this.height, this.vcodec, this.acodec);
|
||||||
|
}
|
||||||
|
SrsPublisher.prototype.stop = function() {
|
||||||
|
for (var i = 0; i < SrsPublisher.__publishers.length; i++) {
|
||||||
|
var player = SrsPublisher.__publishers[i];
|
||||||
|
|
||||||
|
if (player.id != this.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsPublisher.__publishers.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.callbackObj.ref.__stop();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* when publisher ready.
|
||||||
|
* @param cameras a string array contains the names of cameras.
|
||||||
|
* @param microphones a string array contains the names of microphones.
|
||||||
|
*/
|
||||||
|
SrsPublisher.prototype.on_publisher_ready = function(cameras, microphones) {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* when publisher error.
|
||||||
|
* @code the error code.
|
||||||
|
* @desc the error desc message.
|
||||||
|
*/
|
||||||
|
SrsPublisher.prototype.on_publisher_error = function(code, desc) {
|
||||||
|
throw new Error("publisher error. code=" + code + ", desc=" + desc);
|
||||||
|
}
|
||||||
|
SrsPublisher.prototype.on_publisher_warn = function(code, desc) {
|
||||||
|
throw new Error("publisher warn. code=" + code + ", desc=" + desc);
|
||||||
|
}
|
||||||
|
function __srs_find_publisher(id) {
|
||||||
|
for (var i = 0; i < SrsPublisher.__publishers.length; i++) {
|
||||||
|
var publisher = SrsPublisher.__publishers[i];
|
||||||
|
|
||||||
|
if (publisher.id != id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return publisher;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("publisher not found. id=" + id);
|
||||||
|
}
|
||||||
|
function __srs_on_publisher_ready(id, cameras, microphones) {
|
||||||
|
var publisher = __srs_find_publisher(id);
|
||||||
|
|
||||||
|
publisher.cameras = cameras;
|
||||||
|
publisher.microphones = microphones;
|
||||||
|
|
||||||
|
publisher.on_publisher_ready(cameras, microphones);
|
||||||
|
}
|
||||||
|
function __srs_on_publisher_error(id, code) {
|
||||||
|
var publisher = __srs_find_publisher(id);
|
||||||
|
|
||||||
|
publisher.code = code;
|
||||||
|
|
||||||
|
publisher.on_publisher_error(code, publisher.errors[""+code]);
|
||||||
|
}
|
||||||
|
function __srs_on_publisher_warn(id, code) {
|
||||||
|
var publisher = __srs_find_publisher(id);
|
||||||
|
|
||||||
|
publisher.code = code;
|
||||||
|
|
||||||
|
publisher.on_publisher_warn(code, publisher.errors[""+code]);
|
||||||
|
}
|
||||||
681
public/webrtc/srs.sdk.js
Normal file
681
public/webrtc/srs.sdk.js
Normal file
@ -0,0 +1,681 @@
|
|||||||
|
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2021 Winlin
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function SrsError(name, message) {
|
||||||
|
this.name = name;
|
||||||
|
this.message = message;
|
||||||
|
this.stack = (new Error()).stack;
|
||||||
|
}
|
||||||
|
SrsError.prototype = Object.create(Error.prototype);
|
||||||
|
SrsError.prototype.constructor = SrsError;
|
||||||
|
|
||||||
|
// Depends on adapter-7.4.0.min.js from https://github.com/webrtc/adapter
|
||||||
|
// Async-awat-prmise based SRS RTC Publisher.
|
||||||
|
function SrsRtcPublisherAsync() {
|
||||||
|
var self = {};
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
|
||||||
|
self.constraints = {
|
||||||
|
audio: true,
|
||||||
|
video: {
|
||||||
|
width: {ideal: 320, max: 576}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// @see https://github.com/rtcdn/rtcdn-draft
|
||||||
|
// @url The WebRTC url to play with, for example:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream
|
||||||
|
// or specifies the API port:
|
||||||
|
// webrtc://r.ossrs.net:11985/live/livestream
|
||||||
|
// or autostart the publish:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?autostart=true
|
||||||
|
// or change the app from live to myapp:
|
||||||
|
// webrtc://r.ossrs.net:11985/myapp/livestream
|
||||||
|
// or change the stream from livestream to mystream:
|
||||||
|
// webrtc://r.ossrs.net:11985/live/mystream
|
||||||
|
// or set the api server to myapi.domain.com:
|
||||||
|
// webrtc://myapi.domain.com/live/livestream
|
||||||
|
// or set the candidate(eip) of answer:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?candidate=39.107.238.185
|
||||||
|
// or force to access https API:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?schema=https
|
||||||
|
// or use plaintext, without SRTP:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?encrypt=false
|
||||||
|
// or any other information, will pass-by in the query:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?vhost=xxx
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?token=xxx
|
||||||
|
self.publish = async function (url) {
|
||||||
|
var conf = self.__internal.prepareUrl(url);
|
||||||
|
self.pc.addTransceiver("audio", {direction: "sendonly"});
|
||||||
|
self.pc.addTransceiver("video", {direction: "sendonly"});
|
||||||
|
//self.pc.addTransceiver("video", {direction: "sendonly"});
|
||||||
|
//self.pc.addTransceiver("audio", {direction: "sendonly"});
|
||||||
|
|
||||||
|
if (!navigator.mediaDevices && window.location.protocol === 'http:' && window.location.hostname !== 'localhost') {
|
||||||
|
throw new SrsError('HttpsRequiredError', `Please use HTTPS or localhost to publish, read https://github.com/ossrs/srs/issues/2762#issuecomment-983147576`);
|
||||||
|
}
|
||||||
|
var stream = await navigator.mediaDevices.getUserMedia(self.constraints);
|
||||||
|
|
||||||
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
|
stream.getTracks().forEach(function (track) {
|
||||||
|
self.pc.addTrack(track);
|
||||||
|
|
||||||
|
// Notify about local track when stream is ok.
|
||||||
|
self.ontrack && self.ontrack({track: track});
|
||||||
|
});
|
||||||
|
|
||||||
|
var offer = await self.pc.createOffer();
|
||||||
|
await self.pc.setLocalDescription(offer);
|
||||||
|
var session = await new Promise(function (resolve, reject) {
|
||||||
|
// @see https://github.com/rtcdn/rtcdn-draft
|
||||||
|
var data = {
|
||||||
|
api: conf.apiUrl, tid: conf.tid, streamurl: conf.streamUrl,
|
||||||
|
clientip: null, sdp: offer.sdp
|
||||||
|
};
|
||||||
|
console.log("Generated offer: ", data);
|
||||||
|
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.onload = function() {
|
||||||
|
if (xhr.readyState !== xhr.DONE) return;
|
||||||
|
if (xhr.status !== 200 && xhr.status !== 201) return reject(xhr);
|
||||||
|
const data = JSON.parse(xhr.responseText);
|
||||||
|
console.log("Got answer: ", data);
|
||||||
|
return data.code ? reject(xhr) : resolve(data);
|
||||||
|
}
|
||||||
|
xhr.open('POST', conf.apiUrl, true);
|
||||||
|
xhr.setRequestHeader('Content-type', 'application/json');
|
||||||
|
xhr.send(JSON.stringify(data));
|
||||||
|
});
|
||||||
|
await self.pc.setRemoteDescription(
|
||||||
|
new RTCSessionDescription({type: 'answer', sdp: session.sdp})
|
||||||
|
);
|
||||||
|
session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/';
|
||||||
|
|
||||||
|
return session;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close the publisher.
|
||||||
|
self.close = function () {
|
||||||
|
self.pc && self.pc.close();
|
||||||
|
self.pc = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The callback when got local stream.
|
||||||
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
|
self.ontrack = function (event) {
|
||||||
|
// Add track to stream of SDK.
|
||||||
|
self.stream.addTrack(event.track);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal APIs.
|
||||||
|
self.__internal = {
|
||||||
|
defaultPath: '/rtc/v1/publish/',
|
||||||
|
prepareUrl: function (webrtcUrl) {
|
||||||
|
var urlObject = self.__internal.parse(webrtcUrl);
|
||||||
|
|
||||||
|
// If user specifies the schema, use it as API schema.
|
||||||
|
var schema = urlObject.user_query.schema;
|
||||||
|
schema = schema ? schema + ':' : window.location.protocol;
|
||||||
|
|
||||||
|
var port = urlObject.port || 1985;
|
||||||
|
if (schema === 'https:') {
|
||||||
|
port = urlObject.port || 443;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @see https://github.com/rtcdn/rtcdn-draft
|
||||||
|
var api = urlObject.user_query.play || self.__internal.defaultPath;
|
||||||
|
if (api.lastIndexOf('/') !== api.length - 1) {
|
||||||
|
api += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiUrl = schema + '//' + urlObject.server + ':' + port + api;
|
||||||
|
for (var key in urlObject.user_query) {
|
||||||
|
if (key !== 'api' && key !== 'play') {
|
||||||
|
apiUrl += '&' + key + '=' + urlObject.user_query[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
|
||||||
|
apiUrl = apiUrl.replace(api + '&', api + '?');
|
||||||
|
|
||||||
|
var streamUrl = urlObject.url;
|
||||||
|
|
||||||
|
return {
|
||||||
|
apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port,
|
||||||
|
tid: Number(parseInt(new Date().getTime()*Math.random()*100)).toString(16).slice(0, 7)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
parse: function (url) {
|
||||||
|
// @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
|
||||||
|
var a = document.createElement("a");
|
||||||
|
a.href = url.replace("rtmp://", "http://")
|
||||||
|
.replace("webrtc://", "http://")
|
||||||
|
.replace("rtc://", "http://");
|
||||||
|
|
||||||
|
var vhost = a.hostname;
|
||||||
|
var app = a.pathname.substring(1, a.pathname.lastIndexOf("/"));
|
||||||
|
var stream = a.pathname.slice(a.pathname.lastIndexOf("/") + 1);
|
||||||
|
|
||||||
|
// parse the vhost in the params of app, that srs supports.
|
||||||
|
app = app.replace("...vhost...", "?vhost=");
|
||||||
|
if (app.indexOf("?") >= 0) {
|
||||||
|
var params = app.slice(app.indexOf("?"));
|
||||||
|
app = app.slice(0, app.indexOf("?"));
|
||||||
|
|
||||||
|
if (params.indexOf("vhost=") > 0) {
|
||||||
|
vhost = params.slice(params.indexOf("vhost=") + "vhost=".length);
|
||||||
|
if (vhost.indexOf("&") > 0) {
|
||||||
|
vhost = vhost.slice(0, vhost.indexOf("&"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when vhost equals to server, and server is ip,
|
||||||
|
// the vhost is __defaultVhost__
|
||||||
|
if (a.hostname === vhost) {
|
||||||
|
var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
||||||
|
if (re.test(a.hostname)) {
|
||||||
|
vhost = "__defaultVhost__";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the schema
|
||||||
|
var schema = "rtmp";
|
||||||
|
if (url.indexOf("://") > 0) {
|
||||||
|
schema = url.slice(0, url.indexOf("://"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var port = a.port;
|
||||||
|
if (!port) {
|
||||||
|
// Finger out by webrtc url, if contains http or https port, to overwrite default 1985.
|
||||||
|
if (schema === 'webrtc' && url.indexOf(`webrtc://${a.host}:`) === 0) {
|
||||||
|
port = (url.indexOf(`webrtc://${a.host}:80`) === 0) ? 80 : 443;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guess by schema.
|
||||||
|
if (schema === 'http') {
|
||||||
|
port = 80;
|
||||||
|
} else if (schema === 'https') {
|
||||||
|
port = 443;
|
||||||
|
} else if (schema === 'rtmp') {
|
||||||
|
port = 1935;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = {
|
||||||
|
url: url,
|
||||||
|
schema: schema,
|
||||||
|
server: a.hostname, port: port,
|
||||||
|
vhost: vhost, app: app, stream: stream
|
||||||
|
};
|
||||||
|
self.__internal.fill_query(a.search, ret);
|
||||||
|
|
||||||
|
// For webrtc API, we use 443 if page is https, or schema specified it.
|
||||||
|
if (!ret.port) {
|
||||||
|
if (schema === 'webrtc' || schema === 'rtc') {
|
||||||
|
if (ret.user_query.schema === 'https') {
|
||||||
|
ret.port = 443;
|
||||||
|
} else if (window.location.href.indexOf('https://') === 0) {
|
||||||
|
ret.port = 443;
|
||||||
|
} else {
|
||||||
|
// For WebRTC, SRS use 1985 as default API port.
|
||||||
|
ret.port = 1985;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
fill_query: function (query_string, obj) {
|
||||||
|
// pure user query object.
|
||||||
|
obj.user_query = {};
|
||||||
|
|
||||||
|
if (query_string.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split again for angularjs.
|
||||||
|
if (query_string.indexOf("?") >= 0) {
|
||||||
|
query_string = query_string.split("?")[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var queries = query_string.split("&");
|
||||||
|
for (var i = 0; i < queries.length; i++) {
|
||||||
|
var elem = queries[i];
|
||||||
|
|
||||||
|
var query = elem.split("=");
|
||||||
|
obj[query[0]] = query[1];
|
||||||
|
obj.user_query[query[0]] = query[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// alias domain for vhost.
|
||||||
|
if (obj.domain) {
|
||||||
|
obj.vhost = obj.domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pc = new RTCPeerConnection(null);
|
||||||
|
|
||||||
|
// To keep api consistent between player and publisher.
|
||||||
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
|
// @see https://webrtc.org/getting-started/media-devices
|
||||||
|
self.stream = new MediaStream();
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depends on adapter-7.4.0.min.js from https://github.com/webrtc/adapter
|
||||||
|
// Async-await-promise based SRS RTC Player.
|
||||||
|
function SrsRtcPlayerAsync() {
|
||||||
|
var self = {};
|
||||||
|
|
||||||
|
// @see https://github.com/rtcdn/rtcdn-draft
|
||||||
|
// @url The WebRTC url to play with, for example:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream
|
||||||
|
// or specifies the API port:
|
||||||
|
// webrtc://r.ossrs.net:11985/live/livestream
|
||||||
|
// webrtc://r.ossrs.net:80/live/livestream
|
||||||
|
// or autostart the play:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?autostart=true
|
||||||
|
// or change the app from live to myapp:
|
||||||
|
// webrtc://r.ossrs.net:11985/myapp/livestream
|
||||||
|
// or change the stream from livestream to mystream:
|
||||||
|
// webrtc://r.ossrs.net:11985/live/mystream
|
||||||
|
// or set the api server to myapi.domain.com:
|
||||||
|
// webrtc://myapi.domain.com/live/livestream
|
||||||
|
// or set the candidate(eip) of answer:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?candidate=39.107.238.185
|
||||||
|
// or force to access https API:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?schema=https
|
||||||
|
// or use plaintext, without SRTP:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?encrypt=false
|
||||||
|
// or any other information, will pass-by in the query:
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?vhost=xxx
|
||||||
|
// webrtc://r.ossrs.net/live/livestream?token=xxx
|
||||||
|
self.play = async function(url) {
|
||||||
|
var conf = self.__internal.prepareUrl(url);
|
||||||
|
self.pc.addTransceiver("audio", {direction: "recvonly"});
|
||||||
|
self.pc.addTransceiver("video", {direction: "recvonly"});
|
||||||
|
//self.pc.addTransceiver("video", {direction: "recvonly"});
|
||||||
|
//self.pc.addTransceiver("audio", {direction: "recvonly"});
|
||||||
|
|
||||||
|
var offer = await self.pc.createOffer();
|
||||||
|
await self.pc.setLocalDescription(offer);
|
||||||
|
var session = await new Promise(function(resolve, reject) {
|
||||||
|
// @see https://github.com/rtcdn/rtcdn-draft
|
||||||
|
var data = {
|
||||||
|
api: conf.apiUrl, tid: conf.tid, streamurl: conf.streamUrl,
|
||||||
|
clientip: null, sdp: offer.sdp
|
||||||
|
};
|
||||||
|
console.log("Generated offer: ", data);
|
||||||
|
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.onload = function() {
|
||||||
|
if (xhr.readyState !== xhr.DONE) return;
|
||||||
|
if (xhr.status !== 200 && xhr.status !== 201) return reject(xhr);
|
||||||
|
const data = JSON.parse(xhr.responseText);
|
||||||
|
console.log("Got answer: ", data);
|
||||||
|
return data.code ? reject(xhr) : resolve(data);
|
||||||
|
}
|
||||||
|
xhr.open('POST', conf.apiUrl, true);
|
||||||
|
xhr.setRequestHeader('Content-type', 'application/json');
|
||||||
|
xhr.send(JSON.stringify(data));
|
||||||
|
});
|
||||||
|
await self.pc.setRemoteDescription(
|
||||||
|
new RTCSessionDescription({type: 'answer', sdp: session.sdp})
|
||||||
|
);
|
||||||
|
session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/';
|
||||||
|
|
||||||
|
return session;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close the player.
|
||||||
|
self.close = function() {
|
||||||
|
self.pc && self.pc.close();
|
||||||
|
self.pc = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The callback when got remote track.
|
||||||
|
// Note that the onaddstream is deprecated, @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onaddstream
|
||||||
|
self.ontrack = function (event) {
|
||||||
|
// https://webrtc.org/getting-started/remote-streams
|
||||||
|
self.stream.addTrack(event.track);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal APIs.
|
||||||
|
self.__internal = {
|
||||||
|
defaultPath: '/rtc/v1/play/',
|
||||||
|
prepareUrl: function (webrtcUrl) {
|
||||||
|
var urlObject = self.__internal.parse(webrtcUrl);
|
||||||
|
|
||||||
|
// If user specifies the schema, use it as API schema.
|
||||||
|
var schema = urlObject.user_query.schema;
|
||||||
|
schema = schema ? schema + ':' : window.location.protocol;
|
||||||
|
|
||||||
|
var port = urlObject.port || 1985;
|
||||||
|
if (schema === 'https:') {
|
||||||
|
port = urlObject.port || 443;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @see https://github.com/rtcdn/rtcdn-draft
|
||||||
|
var api = urlObject.user_query.play || self.__internal.defaultPath;
|
||||||
|
if (api.lastIndexOf('/') !== api.length - 1) {
|
||||||
|
api += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiUrl = schema + '//' + urlObject.server + ':' + port + api;
|
||||||
|
for (var key in urlObject.user_query) {
|
||||||
|
if (key !== 'api' && key !== 'play') {
|
||||||
|
apiUrl += '&' + key + '=' + urlObject.user_query[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
|
||||||
|
apiUrl = apiUrl.replace(api + '&', api + '?');
|
||||||
|
|
||||||
|
var streamUrl = urlObject.url;
|
||||||
|
|
||||||
|
return {
|
||||||
|
apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port,
|
||||||
|
tid: Number(parseInt(new Date().getTime()*Math.random()*100)).toString(16).slice(0, 7)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
parse: function (url) {
|
||||||
|
// @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
|
||||||
|
var a = document.createElement("a");
|
||||||
|
a.href = url.replace("rtmp://", "http://")
|
||||||
|
.replace("webrtc://", "http://")
|
||||||
|
.replace("rtc://", "http://");
|
||||||
|
|
||||||
|
var vhost = a.hostname;
|
||||||
|
var app = a.pathname.substring(1, a.pathname.lastIndexOf("/"));
|
||||||
|
var stream = a.pathname.slice(a.pathname.lastIndexOf("/") + 1);
|
||||||
|
|
||||||
|
// parse the vhost in the params of app, that srs supports.
|
||||||
|
app = app.replace("...vhost...", "?vhost=");
|
||||||
|
if (app.indexOf("?") >= 0) {
|
||||||
|
var params = app.slice(app.indexOf("?"));
|
||||||
|
app = app.slice(0, app.indexOf("?"));
|
||||||
|
|
||||||
|
if (params.indexOf("vhost=") > 0) {
|
||||||
|
vhost = params.slice(params.indexOf("vhost=") + "vhost=".length);
|
||||||
|
if (vhost.indexOf("&") > 0) {
|
||||||
|
vhost = vhost.slice(0, vhost.indexOf("&"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when vhost equals to server, and server is ip,
|
||||||
|
// the vhost is __defaultVhost__
|
||||||
|
if (a.hostname === vhost) {
|
||||||
|
var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
||||||
|
if (re.test(a.hostname)) {
|
||||||
|
vhost = "__defaultVhost__";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the schema
|
||||||
|
var schema = "rtmp";
|
||||||
|
if (url.indexOf("://") > 0) {
|
||||||
|
schema = url.slice(0, url.indexOf("://"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var port = a.port;
|
||||||
|
if (!port) {
|
||||||
|
// Finger out by webrtc url, if contains http or https port, to overwrite default 1985.
|
||||||
|
if (schema === 'webrtc' && url.indexOf(`webrtc://${a.host}:`) === 0) {
|
||||||
|
port = (url.indexOf(`webrtc://${a.host}:80`) === 0) ? 80 : 443;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guess by schema.
|
||||||
|
if (schema === 'http') {
|
||||||
|
port = 80;
|
||||||
|
} else if (schema === 'https') {
|
||||||
|
port = 443;
|
||||||
|
} else if (schema === 'rtmp') {
|
||||||
|
port = 1935;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = {
|
||||||
|
url: url,
|
||||||
|
schema: schema,
|
||||||
|
server: a.hostname, port: port,
|
||||||
|
vhost: vhost, app: app, stream: stream
|
||||||
|
};
|
||||||
|
self.__internal.fill_query(a.search, ret);
|
||||||
|
|
||||||
|
// For webrtc API, we use 443 if page is https, or schema specified it.
|
||||||
|
if (!ret.port) {
|
||||||
|
if (schema === 'webrtc' || schema === 'rtc') {
|
||||||
|
if (ret.user_query.schema === 'https') {
|
||||||
|
ret.port = 443;
|
||||||
|
} else if (window.location.href.indexOf('https://') === 0) {
|
||||||
|
ret.port = 443;
|
||||||
|
} else {
|
||||||
|
// For WebRTC, SRS use 1985 as default API port.
|
||||||
|
ret.port = 1985;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
fill_query: function (query_string, obj) {
|
||||||
|
// pure user query object.
|
||||||
|
obj.user_query = {};
|
||||||
|
|
||||||
|
if (query_string.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split again for angularjs.
|
||||||
|
if (query_string.indexOf("?") >= 0) {
|
||||||
|
query_string = query_string.split("?")[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var queries = query_string.split("&");
|
||||||
|
for (var i = 0; i < queries.length; i++) {
|
||||||
|
var elem = queries[i];
|
||||||
|
|
||||||
|
var query = elem.split("=");
|
||||||
|
obj[query[0]] = query[1];
|
||||||
|
obj.user_query[query[0]] = query[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// alias domain for vhost.
|
||||||
|
if (obj.domain) {
|
||||||
|
obj.vhost = obj.domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pc = new RTCPeerConnection(null);
|
||||||
|
|
||||||
|
// Create a stream to add track to the stream, @see https://webrtc.org/getting-started/remote-streams
|
||||||
|
self.stream = new MediaStream();
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/ontrack
|
||||||
|
self.pc.ontrack = function(event) {
|
||||||
|
if (self.ontrack) {
|
||||||
|
self.ontrack(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depends on adapter-7.4.0.min.js from https://github.com/webrtc/adapter
|
||||||
|
// Async-awat-prmise based SRS RTC Publisher by WHIP.
|
||||||
|
function SrsRtcWhipWhepAsync() {
|
||||||
|
var self = {};
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
|
||||||
|
self.constraints = {
|
||||||
|
audio: true,
|
||||||
|
video: {
|
||||||
|
width: {ideal: 320, max: 576}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// See https://datatracker.ietf.org/doc/draft-ietf-wish-whip/
|
||||||
|
// @url The WebRTC url to publish with, for example:
|
||||||
|
// http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream
|
||||||
|
self.publish = async function (url) {
|
||||||
|
if (url.indexOf('/whip/') === -1) throw new Error(`invalid WHIP url ${url}`);
|
||||||
|
|
||||||
|
self.pc.addTransceiver("audio", {direction: "sendonly"});
|
||||||
|
self.pc.addTransceiver("video", {direction: "sendonly"});
|
||||||
|
|
||||||
|
if (!navigator.mediaDevices && window.location.protocol === 'http:' && window.location.hostname !== 'localhost') {
|
||||||
|
throw new SrsError('HttpsRequiredError', `Please use HTTPS or localhost to publish, read https://github.com/ossrs/srs/issues/2762#issuecomment-983147576`);
|
||||||
|
}
|
||||||
|
var stream = await navigator.mediaDevices.getUserMedia(self.constraints);
|
||||||
|
|
||||||
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
|
stream.getTracks().forEach(function (track) {
|
||||||
|
self.pc.addTrack(track);
|
||||||
|
|
||||||
|
// Notify about local track when stream is ok.
|
||||||
|
self.ontrack && self.ontrack({track: track});
|
||||||
|
});
|
||||||
|
|
||||||
|
var offer = await self.pc.createOffer();
|
||||||
|
await self.pc.setLocalDescription(offer);
|
||||||
|
const answer = await new Promise(function (resolve, reject) {
|
||||||
|
console.log("Generated offer: ", offer);
|
||||||
|
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.onload = function() {
|
||||||
|
if (xhr.readyState !== xhr.DONE) return;
|
||||||
|
if (xhr.status !== 200 && xhr.status !== 201) return reject(xhr);
|
||||||
|
const data = xhr.responseText;
|
||||||
|
console.log("Got answer: ", data);
|
||||||
|
return data.code ? reject(xhr) : resolve(data);
|
||||||
|
}
|
||||||
|
xhr.open('POST', url, true);
|
||||||
|
xhr.setRequestHeader('Content-type', 'application/sdp');
|
||||||
|
xhr.send(offer.sdp);
|
||||||
|
});
|
||||||
|
await self.pc.setRemoteDescription(
|
||||||
|
new RTCSessionDescription({type: 'answer', sdp: answer})
|
||||||
|
);
|
||||||
|
|
||||||
|
return self.__internal.parseId(url, offer.sdp, answer);
|
||||||
|
};
|
||||||
|
|
||||||
|
// See https://datatracker.ietf.org/doc/draft-ietf-wish-whip/
|
||||||
|
// @url The WebRTC url to play with, for example:
|
||||||
|
// http://localhost:1985/rtc/v1/whep/?app=live&stream=livestream
|
||||||
|
self.play = async function(url) {
|
||||||
|
if (url.indexOf('/whip-play/') === -1 && url.indexOf('/whep/') === -1) throw new Error(`invalid WHEP url ${url}`);
|
||||||
|
|
||||||
|
self.pc.addTransceiver("audio", {direction: "recvonly"});
|
||||||
|
self.pc.addTransceiver("video", {direction: "recvonly"});
|
||||||
|
|
||||||
|
var offer = await self.pc.createOffer();
|
||||||
|
await self.pc.setLocalDescription(offer);
|
||||||
|
const answer = await new Promise(function(resolve, reject) {
|
||||||
|
console.log("Generated offer: ", offer);
|
||||||
|
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.onload = function() {
|
||||||
|
if (xhr.readyState !== xhr.DONE) return;
|
||||||
|
if (xhr.status !== 200 && xhr.status !== 201) return reject(xhr);
|
||||||
|
const data = xhr.responseText;
|
||||||
|
console.log("Got answer: ", data);
|
||||||
|
return data.code ? reject(xhr) : resolve(data);
|
||||||
|
}
|
||||||
|
xhr.open('POST', url, true);
|
||||||
|
xhr.setRequestHeader('Content-type', 'application/sdp');
|
||||||
|
xhr.send(offer.sdp);
|
||||||
|
});
|
||||||
|
await self.pc.setRemoteDescription(
|
||||||
|
new RTCSessionDescription({type: 'answer', sdp: answer})
|
||||||
|
);
|
||||||
|
|
||||||
|
return self.__internal.parseId(url, offer.sdp, answer);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close the publisher.
|
||||||
|
self.close = function () {
|
||||||
|
self.pc && self.pc.close();
|
||||||
|
self.pc = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The callback when got local stream.
|
||||||
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
|
self.ontrack = function (event) {
|
||||||
|
// Add track to stream of SDK.
|
||||||
|
self.stream.addTrack(event.track);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pc = new RTCPeerConnection(null);
|
||||||
|
|
||||||
|
// To keep api consistent between player and publisher.
|
||||||
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
|
// @see https://webrtc.org/getting-started/media-devices
|
||||||
|
self.stream = new MediaStream();
|
||||||
|
|
||||||
|
// Internal APIs.
|
||||||
|
self.__internal = {
|
||||||
|
parseId: (url, offer, answer) => {
|
||||||
|
let sessionid = offer.substr(offer.indexOf('a=ice-ufrag:') + 'a=ice-ufrag:'.length);
|
||||||
|
sessionid = sessionid.substr(0, sessionid.indexOf('\n') - 1) + ':';
|
||||||
|
sessionid += answer.substr(answer.indexOf('a=ice-ufrag:') + 'a=ice-ufrag:'.length);
|
||||||
|
sessionid = sessionid.substr(0, sessionid.indexOf('\n'));
|
||||||
|
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
return {
|
||||||
|
sessionid: sessionid, // Should be ice-ufrag of answer:offer.
|
||||||
|
simulator: a.protocol + '//' + a.host + '/rtc/v1/nack/',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/ontrack
|
||||||
|
self.pc.ontrack = function(event) {
|
||||||
|
if (self.ontrack) {
|
||||||
|
self.ontrack(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the codec of RTCRtpSender, kind(audio/video) is optional filter.
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#getting_the_supported_codecs
|
||||||
|
function SrsRtcFormatSenders(senders, kind) {
|
||||||
|
var codecs = [];
|
||||||
|
senders.forEach(function (sender) {
|
||||||
|
var params = sender.getParameters();
|
||||||
|
params && params.codecs && params.codecs.forEach(function(c) {
|
||||||
|
if (kind && sender.track.kind !== kind) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.mimeType.indexOf('/red') > 0 || c.mimeType.indexOf('/rtx') > 0 || c.mimeType.indexOf('/fec') > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var s = '';
|
||||||
|
|
||||||
|
s += c.mimeType.replace('audio/', '').replace('video/', '');
|
||||||
|
s += ', ' + c.clockRate + 'HZ';
|
||||||
|
if (sender.track.kind === "audio") {
|
||||||
|
s += ', channels: ' + c.channels;
|
||||||
|
}
|
||||||
|
s += ', pt: ' + c.payloadType;
|
||||||
|
|
||||||
|
codecs.push(s);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return codecs.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
8
public/webrtc/srs.utility.js
Normal file
8
public/webrtc/srs.utility.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* parse the rtmp url,
|
||||||
|
* for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
|
||||||
|
* @return object {server, port, vhost, app, stream}
|
||||||
|
*/
|
||||||
|
function srs_parse_rtmp_url(rtmp_url) {
|
||||||
|
return parse_rtmp_url(rtmp_url);
|
||||||
|
}
|
||||||
4
public/webrtc/swfobject.js
Normal file
4
public/webrtc/swfobject.js
Normal file
File diff suppressed because one or more lines are too long
686
public/webrtc/winlin.utility.js
Normal file
686
public/webrtc/winlin.utility.js
Normal file
@ -0,0 +1,686 @@
|
|||||||
|
// winlin.utility.js
|
||||||
|
|
||||||
|
/**
|
||||||
|
* common utilities
|
||||||
|
* depends: jquery1.10
|
||||||
|
* https://gitee.com/winlinvip/codes/rpn0c2ewbomj81augzk4y59
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
* v 1.0.23
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* padding the output.
|
||||||
|
* padding(3, 5, '0') is 00003
|
||||||
|
* padding(3, 5, 'x') is xxxx3
|
||||||
|
* @see http://blog.csdn.net/win_lin/article/details/12065413
|
||||||
|
*/
|
||||||
|
function padding(number, length, prefix) {
|
||||||
|
if(String(number).length >= length){
|
||||||
|
return String(number);
|
||||||
|
}
|
||||||
|
return padding(prefix+number, length, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extends system array, to remove all specified elem.
|
||||||
|
* @param arr the array to remove elem from.
|
||||||
|
* @param elem the elem to remove.
|
||||||
|
* @remark all elem will be removed.
|
||||||
|
* for example,
|
||||||
|
* arr = [10, 15, 20, 30, 20, 40]
|
||||||
|
* system_array_remove(arr, 10) // arr=[15, 20, 30, 20, 40]
|
||||||
|
* system_array_remove(arr, 20) // arr=[15, 30, 40]
|
||||||
|
*/
|
||||||
|
function system_array_remove(arr, elem) {
|
||||||
|
if (!arr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var removed = true;
|
||||||
|
var i = 0;
|
||||||
|
while (removed) {
|
||||||
|
removed = false;
|
||||||
|
for (; i < arr.length; i++) {
|
||||||
|
if (elem == arr[i]) {
|
||||||
|
arr.splice(i, 1);
|
||||||
|
removed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether the array contains specified element.
|
||||||
|
* @param arr the array to find.
|
||||||
|
* @param elem_or_function the element value or compare function.
|
||||||
|
* @returns true contains elem; otherwise false.
|
||||||
|
* for example,
|
||||||
|
* arr = [10, 15, 20, 30, 20, 40]
|
||||||
|
* system_array_contains(arr, 10) // true
|
||||||
|
* system_array_contains(arr, 11) // false
|
||||||
|
* system_array_contains(arr, function(elem){return elem == 30;}); // true
|
||||||
|
* system_array_contains(arr, function(elem){return elem == 60;}); // false
|
||||||
|
*/
|
||||||
|
function system_array_contains(arr, elem_or_function) {
|
||||||
|
return system_array_get(arr, elem_or_function) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the specified element from array
|
||||||
|
* @param arr the array to find.
|
||||||
|
* @param elem_or_function the element value or compare function.
|
||||||
|
* @returns the matched elem; otherwise null.
|
||||||
|
* for example,
|
||||||
|
* arr = [10, 15, 20, 30, 20, 40]
|
||||||
|
* system_array_get(arr, 10) // 10
|
||||||
|
* system_array_get(arr, 11) // null
|
||||||
|
* system_array_get(arr, function(elem){return elem == 30;}); // 30
|
||||||
|
* system_array_get(arr, function(elem){return elem == 60;}); // null
|
||||||
|
*/
|
||||||
|
function system_array_get(arr, elem_or_function) {
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
if (typeof elem_or_function == "function") {
|
||||||
|
if (elem_or_function(arr[i])) {
|
||||||
|
return arr[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (elem_or_function == arr[i]) {
|
||||||
|
return arr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* to iterate on array.
|
||||||
|
* @param arr the array to iterate on.
|
||||||
|
* @param pfn the function to apply on it. return false to break loop.
|
||||||
|
* for example,
|
||||||
|
* arr = [10, 15, 20, 30, 20, 40]
|
||||||
|
* system_array_foreach(arr, function(elem, index){
|
||||||
|
* console.log('index=' + index + ',elem=' + elem);
|
||||||
|
* });
|
||||||
|
* @return true when iterate all elems.
|
||||||
|
*/
|
||||||
|
function system_array_foreach(arr, pfn) {
|
||||||
|
if (!pfn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
if (!pfn(arr[i], i)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether the str starts with flag.
|
||||||
|
*/
|
||||||
|
function system_string_startswith(str, flag) {
|
||||||
|
if (typeof flag == "object" && flag.constructor == Array) {
|
||||||
|
for (var i = 0; i < flag.length; i++) {
|
||||||
|
if (system_string_startswith(str, flag[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str && flag && str.length >= flag.length && str.indexOf(flag) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether the str ends with flag.
|
||||||
|
*/
|
||||||
|
function system_string_endswith(str, flag) {
|
||||||
|
if (typeof flag == "object" && flag.constructor == Array) {
|
||||||
|
for (var i = 0; i < flag.length; i++) {
|
||||||
|
if (system_string_endswith(str, flag[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str && flag && str.length >= flag.length && str.indexOf(flag) == str.length - flag.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* trim the start and end of flag in str.
|
||||||
|
* @param flag a string to trim.
|
||||||
|
*/
|
||||||
|
function system_string_trim(str, flag) {
|
||||||
|
if (!flag || !flag.length || typeof flag != "string") {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (system_string_startswith(str, flag)) {
|
||||||
|
str = str.slice(flag.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (system_string_endswith(str, flag)) {
|
||||||
|
str = str.slice(0, str.length - flag.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* array sort asc, for example:
|
||||||
|
* [a, b] in [10, 11, 9]
|
||||||
|
* then sort to: [9, 10, 11]
|
||||||
|
* Usage, for example:
|
||||||
|
obj.data.data.sort(function(a, b){
|
||||||
|
return array_sort_asc(a.metadata.meta_id, b.metadata.meta_id);
|
||||||
|
});
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
* @remark, if need desc, use -1*array_sort_asc(a,b)
|
||||||
|
*/
|
||||||
|
function array_sort_asc(elem_a, elem_b) {
|
||||||
|
if (elem_a > elem_b) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return (elem_a < elem_b)? -1 : 0;
|
||||||
|
}
|
||||||
|
function array_sort_desc(elem_a, elem_b) {
|
||||||
|
return -1 * array_sort_asc(elem_a, elem_b);
|
||||||
|
}
|
||||||
|
function system_array_sort_asc(elem_a, elem_b) {
|
||||||
|
return array_sort_asc(elem_a, elem_b);
|
||||||
|
}
|
||||||
|
function system_array_sort_desc(elem_a, elem_b) {
|
||||||
|
return -1 * array_sort_asc(elem_a, elem_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse the query string to object.
|
||||||
|
* parse the url location object as: host(hostname:http_port), pathname(dir/filename)
|
||||||
|
* for example, url http://192.168.1.168:1980/ui/players.html?vhost=player.vhost.com&app=test&stream=livestream
|
||||||
|
* parsed to object:
|
||||||
|
{
|
||||||
|
host : "192.168.1.168:1980",
|
||||||
|
hostname : "192.168.1.168",
|
||||||
|
http_port : 1980,
|
||||||
|
pathname : "/ui/players.html",
|
||||||
|
dir : "/ui",
|
||||||
|
filename : "/players.html",
|
||||||
|
|
||||||
|
vhost : "player.vhost.com",
|
||||||
|
app : "test",
|
||||||
|
stream : "livestream"
|
||||||
|
}
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
*/
|
||||||
|
function parse_query_string(){
|
||||||
|
var obj = {};
|
||||||
|
|
||||||
|
// add the uri object.
|
||||||
|
// parse the host(hostname:http_port), pathname(dir/filename)
|
||||||
|
obj.host = window.location.host;
|
||||||
|
obj.hostname = window.location.hostname;
|
||||||
|
obj.http_port = (window.location.port == "")? 80:window.location.port;
|
||||||
|
obj.pathname = window.location.pathname;
|
||||||
|
if (obj.pathname.lastIndexOf("/") <= 0) {
|
||||||
|
obj.dir = "/";
|
||||||
|
obj.filename = "";
|
||||||
|
} else {
|
||||||
|
obj.dir = obj.pathname.slice(0, obj.pathname.lastIndexOf("/"));
|
||||||
|
obj.filename = obj.pathname.slice(obj.pathname.lastIndexOf("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// pure user query object.
|
||||||
|
obj.user_query = {};
|
||||||
|
|
||||||
|
// parse the query string.
|
||||||
|
var query_string = String(window.location.search).replace(" ", "").split("?")[1];
|
||||||
|
if(query_string === undefined){
|
||||||
|
query_string = String(window.location.hash).replace(" ", "").split("#")[1];
|
||||||
|
if(query_string === undefined){
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__fill_query(query_string, obj);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __fill_query(query_string, obj) {
|
||||||
|
// pure user query object.
|
||||||
|
obj.user_query = {};
|
||||||
|
|
||||||
|
if (query_string.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split again for angularjs.
|
||||||
|
if (query_string.indexOf("?") >= 0) {
|
||||||
|
query_string = query_string.split("?")[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var queries = query_string.split("&");
|
||||||
|
for (var i = 0; i < queries.length; i++) {
|
||||||
|
var elem = queries[i];
|
||||||
|
|
||||||
|
var query = elem.split("=");
|
||||||
|
obj[query[0]] = query[1];
|
||||||
|
obj.user_query[query[0]] = query[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// alias domain for vhost.
|
||||||
|
if (obj.domain) {
|
||||||
|
obj.vhost = obj.domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse the rtmp url,
|
||||||
|
* for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
|
||||||
|
* @return object {server, port, vhost, app, stream}
|
||||||
|
* for exmaple, rtmp_url is rtmp://demo.srs.com:1935/live...vhost...players/livestream
|
||||||
|
* parsed to object:
|
||||||
|
{
|
||||||
|
server: "demo.srs.com",
|
||||||
|
port: 1935,
|
||||||
|
vhost: "players",
|
||||||
|
app: "live",
|
||||||
|
stream: "livestream"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
function parse_rtmp_url(rtmp_url) {
|
||||||
|
// @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
|
||||||
|
var a = document.createElement("a");
|
||||||
|
a.href = rtmp_url.replace("rtmp://", "http://")
|
||||||
|
.replace("webrtc://", "http://")
|
||||||
|
.replace("rtc://", "http://");
|
||||||
|
|
||||||
|
var vhost = a.hostname;
|
||||||
|
var app = a.pathname.substring(1, a.pathname.lastIndexOf("/"));
|
||||||
|
var stream = a.pathname.slice(a.pathname.lastIndexOf("/") + 1);
|
||||||
|
|
||||||
|
// parse the vhost in the params of app, that srs supports.
|
||||||
|
app = app.replace("...vhost...", "?vhost=");
|
||||||
|
if (app.indexOf("?") >= 0) {
|
||||||
|
var params = app.slice(app.indexOf("?"));
|
||||||
|
app = app.slice(0, app.indexOf("?"));
|
||||||
|
|
||||||
|
if (params.indexOf("vhost=") > 0) {
|
||||||
|
vhost = params.slice(params.indexOf("vhost=") + "vhost=".length);
|
||||||
|
if (vhost.indexOf("&") > 0) {
|
||||||
|
vhost = vhost.slice(0, vhost.indexOf("&"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when vhost equals to server, and server is ip,
|
||||||
|
// the vhost is __defaultVhost__
|
||||||
|
if (a.hostname === vhost) {
|
||||||
|
var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
||||||
|
if (re.test(a.hostname)) {
|
||||||
|
vhost = "__defaultVhost__";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the schema
|
||||||
|
var schema = "rtmp";
|
||||||
|
if (rtmp_url.indexOf("://") > 0) {
|
||||||
|
schema = rtmp_url.slice(0, rtmp_url.indexOf("://"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var port = a.port;
|
||||||
|
if (!port) {
|
||||||
|
if (schema === 'http') {
|
||||||
|
port = 80;
|
||||||
|
} else if (schema === 'https') {
|
||||||
|
port = 443;
|
||||||
|
} else if (schema === 'rtmp') {
|
||||||
|
port = 1935;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = {
|
||||||
|
url: rtmp_url,
|
||||||
|
schema: schema,
|
||||||
|
server: a.hostname, port: port,
|
||||||
|
vhost: vhost, app: app, stream: stream
|
||||||
|
};
|
||||||
|
__fill_query(a.search, ret);
|
||||||
|
|
||||||
|
// For webrtc API, we use 443 if page is https, or schema specified it.
|
||||||
|
if (!ret.port) {
|
||||||
|
if (schema === 'webrtc' || schema === 'rtc') {
|
||||||
|
if (ret.user_query.schema === 'https') {
|
||||||
|
ret.port = 443;
|
||||||
|
} else if (window.location.href.indexOf('https://') === 0) {
|
||||||
|
ret.port = 443;
|
||||||
|
} else {
|
||||||
|
// For WebRTC, SRS use 1985 as default API port.
|
||||||
|
ret.port = 1985;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the agent.
|
||||||
|
* @return an object specifies some browser.
|
||||||
|
* for example, get_browser_agents().MSIE
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
*/
|
||||||
|
function get_browser_agents() {
|
||||||
|
var agent = navigator.userAgent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
WindowsPC platform, Win7:
|
||||||
|
chrome 31.0.1650.63:
|
||||||
|
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
|
||||||
|
(KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
|
||||||
|
firefox 23.0.1:
|
||||||
|
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101
|
||||||
|
Firefox/23.0
|
||||||
|
safari 5.1.7(7534.57.2):
|
||||||
|
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2
|
||||||
|
(KHTML, like Gecko) Version/5.1.7 Safari/534.57.2
|
||||||
|
opera 15.0.1147.153:
|
||||||
|
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
|
||||||
|
(KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
|
||||||
|
OPR/15.0.1147.153
|
||||||
|
360 6.2.1.272:
|
||||||
|
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
|
||||||
|
Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
|
||||||
|
.NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
|
||||||
|
.NET4.0E)
|
||||||
|
IE 10.0.9200.16750(update: 10.0.12):
|
||||||
|
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
|
||||||
|
Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
|
||||||
|
.NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
|
||||||
|
.NET4.0E)
|
||||||
|
*/
|
||||||
|
|
||||||
|
return {
|
||||||
|
// platform
|
||||||
|
Android: agent.indexOf("Android") != -1,
|
||||||
|
Windows: agent.indexOf("Windows") != -1,
|
||||||
|
iPhone: agent.indexOf("iPhone") != -1,
|
||||||
|
// Windows Browsers
|
||||||
|
Chrome: agent.indexOf("Chrome") != -1,
|
||||||
|
Firefox: agent.indexOf("Firefox") != -1,
|
||||||
|
QQBrowser: agent.indexOf("QQBrowser") != -1,
|
||||||
|
MSIE: agent.indexOf("MSIE") != -1,
|
||||||
|
// Android Browsers
|
||||||
|
Opera: agent.indexOf("Presto") != -1,
|
||||||
|
MQQBrowser: agent.indexOf("MQQBrowser") != -1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* format relative seconds to HH:MM:SS,
|
||||||
|
* for example, 210s formated to 00:03:30
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
* @usage relative_seconds_to_HHMMSS(210)
|
||||||
|
*/
|
||||||
|
function relative_seconds_to_HHMMSS(seconds){
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(Number(seconds) * 1000);
|
||||||
|
|
||||||
|
var ret = padding(date.getUTCHours(), 2, '0')
|
||||||
|
+ ":" + padding(date.getUTCMinutes(), 2, '0')
|
||||||
|
+ ":" + padding(date.getUTCSeconds(), 2, '0');
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* format absolute seconds to HH:MM:SS,
|
||||||
|
* for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 10:01:20
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
* @usage absolute_seconds_to_HHMMSS(new Date().getTime() / 1000)
|
||||||
|
*/
|
||||||
|
function absolute_seconds_to_HHMMSS(seconds){
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(Number(seconds) * 1000);
|
||||||
|
|
||||||
|
var ret = padding(date.getHours(), 2, '0')
|
||||||
|
+ ":" + padding(date.getMinutes(), 2, '0')
|
||||||
|
+ ":" + padding(date.getSeconds(), 2, '0');
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* format absolute seconds to YYYY-mm-dd,
|
||||||
|
* for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 2014-01-08
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
* @usage absolute_seconds_to_YYYYmmdd(new Date().getTime() / 1000)
|
||||||
|
*/
|
||||||
|
function absolute_seconds_to_YYYYmmdd(seconds) {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(Number(seconds) * 1000);
|
||||||
|
|
||||||
|
var ret = date.getFullYear()
|
||||||
|
+ "-" + padding(date.getMonth() + 1, 2, '0')
|
||||||
|
+ "-" + padding(date.getDate(), 2, '0');
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse the date in str to Date object.
|
||||||
|
* @param str the date in str, format as "YYYY-mm-dd", for example, 2014-12-11
|
||||||
|
* @returns a date object.
|
||||||
|
* @usage YYYYmmdd_parse("2014-12-11")
|
||||||
|
*/
|
||||||
|
function YYYYmmdd_parse(str) {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(Date.parse(str));
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* async refresh function call. to avoid multiple call.
|
||||||
|
* @remark AsyncRefresh is for jquery to refresh the speicified pfn in a page;
|
||||||
|
* if angularjs, use AsyncRefresh2 to change pfn, cancel previous request for angularjs use singleton object.
|
||||||
|
* @param refresh_interval the default refresh interval ms.
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
* the pfn can be implements as following:
|
||||||
|
var async_refresh = new AsyncRefresh(pfn, 3000);
|
||||||
|
function pfn() {
|
||||||
|
if (!async_refresh.refresh_is_enabled()) {
|
||||||
|
async_refresh.request(100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET', async: true, url: 'xxxxx',
|
||||||
|
complete: function(){
|
||||||
|
if (!async_refresh.refresh_is_enabled()) {
|
||||||
|
async_refresh.request(0);
|
||||||
|
} else {
|
||||||
|
async_refresh.request(async_refresh.refresh_interval);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
success: function(res){
|
||||||
|
// if donot allow refresh, directly return.
|
||||||
|
if (!async_refresh.refresh_is_enabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// render the res.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
function AsyncRefresh(pfn, refresh_interval) {
|
||||||
|
this.refresh_interval = refresh_interval;
|
||||||
|
|
||||||
|
this.__handler = null;
|
||||||
|
this.__pfn = pfn;
|
||||||
|
|
||||||
|
this.__enabled = true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* disable the refresher, the pfn must check the refresh state.
|
||||||
|
*/
|
||||||
|
AsyncRefresh.prototype.refresh_disable = function() {
|
||||||
|
this.__enabled = false;
|
||||||
|
}
|
||||||
|
AsyncRefresh.prototype.refresh_enable = function() {
|
||||||
|
this.__enabled = true;
|
||||||
|
}
|
||||||
|
AsyncRefresh.prototype.refresh_is_enabled = function() {
|
||||||
|
return this.__enabled;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* start new async request
|
||||||
|
* @param timeout the timeout in ms.
|
||||||
|
* user can use the refresh_interval of the AsyncRefresh object,
|
||||||
|
* which initialized in constructor.
|
||||||
|
*/
|
||||||
|
AsyncRefresh.prototype.request = function(timeout) {
|
||||||
|
if (this.__handler) {
|
||||||
|
clearTimeout(this.__handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__handler = setTimeout(this.__pfn, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* async refresh v2, support cancellable refresh, and change the refresh pfn.
|
||||||
|
* @remakr for angularjs. if user only need jquery, maybe AsyncRefresh is better.
|
||||||
|
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||||
|
* Usage:
|
||||||
|
bsmControllers.controller('CServers', ['$scope', 'MServer', function($scope, MServer){
|
||||||
|
async_refresh2.refresh_change(function(){
|
||||||
|
// 获取服务器列表
|
||||||
|
MServer.servers_load({}, function(data){
|
||||||
|
$scope.servers = data.data.servers;
|
||||||
|
async_refresh2.request();
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
async_refresh2.request(0);
|
||||||
|
}]);
|
||||||
|
bsmControllers.controller('CStreams', ['$scope', 'MStream', function($scope, MStream){
|
||||||
|
async_refresh2.refresh_change(function(){
|
||||||
|
// 获取流列表
|
||||||
|
MStream.streams_load({}, function(data){
|
||||||
|
$scope.streams = data.data.streams;
|
||||||
|
async_refresh2.request();
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
async_refresh2.request(0);
|
||||||
|
}]);
|
||||||
|
*/
|
||||||
|
function AsyncRefresh2() {
|
||||||
|
/**
|
||||||
|
* the function callback before call the pfn.
|
||||||
|
* the protype is function():bool, which return true to invoke, false to abort the call.
|
||||||
|
* null to ignore this callback.
|
||||||
|
*
|
||||||
|
* for example, user can abort the refresh by find the class popover:
|
||||||
|
* async_refresh2.on_before_call_pfn = function() {
|
||||||
|
* if ($(".popover").length > 0) {
|
||||||
|
* async_refresh2.request();
|
||||||
|
* return false;
|
||||||
|
* }
|
||||||
|
* return true;
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
this.on_before_call_pfn = null;
|
||||||
|
|
||||||
|
// use a anonymous function to call, and check the enabled when actually invoke.
|
||||||
|
this.__call = {
|
||||||
|
pfn: null,
|
||||||
|
timeout: 0,
|
||||||
|
__enabled: false,
|
||||||
|
__handler: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// singleton
|
||||||
|
var async_refresh2 = new AsyncRefresh2();
|
||||||
|
/**
|
||||||
|
* initialize or refresh change. cancel previous request, setup new request.
|
||||||
|
* @param pfn a function():void to request after timeout. null to disable refresher.
|
||||||
|
* @param timeout the timeout in ms, to call pfn. null to disable refresher.
|
||||||
|
*/
|
||||||
|
AsyncRefresh2.prototype.initialize = function(pfn, timeout) {
|
||||||
|
this.refresh_change(pfn, timeout);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* stop refresh, the refresh pfn is set to null.
|
||||||
|
*/
|
||||||
|
AsyncRefresh2.prototype.stop = function() {
|
||||||
|
this.__call.__enabled = false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* restart refresh, use previous config.
|
||||||
|
*/
|
||||||
|
AsyncRefresh2.prototype.restart = function() {
|
||||||
|
this.__call.__enabled = true;
|
||||||
|
this.request(0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* change refresh pfn, the old pfn will set to disabled.
|
||||||
|
*/
|
||||||
|
AsyncRefresh2.prototype.refresh_change = function(pfn, timeout) {
|
||||||
|
// cancel the previous call.
|
||||||
|
if (this.__call.__handler) {
|
||||||
|
clearTimeout(this.__handler);
|
||||||
|
}
|
||||||
|
this.__call.__enabled = false;
|
||||||
|
|
||||||
|
// setup new call.
|
||||||
|
this.__call = {
|
||||||
|
pfn: pfn,
|
||||||
|
timeout: timeout,
|
||||||
|
__enabled: true,
|
||||||
|
__handler: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* start new request, we never auto start the request,
|
||||||
|
* user must start new request when previous completed.
|
||||||
|
* @param timeout [optional] if not specified, use the timeout in initialize or refresh_change.
|
||||||
|
*/
|
||||||
|
AsyncRefresh2.prototype.request = function(timeout) {
|
||||||
|
var self = this;
|
||||||
|
var this_call = this.__call;
|
||||||
|
|
||||||
|
// clear previous timeout.
|
||||||
|
if (this_call.__handler) {
|
||||||
|
clearTimeout(this_call.__handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// override the timeout
|
||||||
|
if (timeout == undefined) {
|
||||||
|
timeout = this_call.timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if user disabled refresher.
|
||||||
|
if (this_call.pfn == null || timeout == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this_call.__handler = setTimeout(function(){
|
||||||
|
// cancelled by refresh_change, ignore.
|
||||||
|
if (!this_call.__enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback if the handler installled.
|
||||||
|
if (self.on_before_call_pfn) {
|
||||||
|
if (!self.on_before_call_pfn()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the actual call.
|
||||||
|
this_call.pfn();
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
63
src/api/drone/droneConfig/index.ts
Normal file
63
src/api/drone/droneConfig/index.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import { AxiosPromise } from 'axios';
|
||||||
|
import { DroneConfigVO, DroneConfigForm, DroneConfigQuery } from '@/api/drone/droneConfig/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询无人机配置列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listDroneConfig = (query?: DroneConfigQuery): AxiosPromise<DroneConfigVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/drone/droneConfig/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询无人机配置详细
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getDroneConfig = (id: string | number): AxiosPromise<DroneConfigVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/drone/droneConfig/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增无人机配置
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addDroneConfig = (data: DroneConfigForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/drone/droneConfig',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改无人机配置
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateDroneConfig = (data: DroneConfigForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/drone/droneConfig',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除无人机配置
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delDroneConfig = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/drone/droneConfig/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
80
src/api/drone/droneConfig/types.ts
Normal file
80
src/api/drone/droneConfig/types.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
export interface DroneConfigVO {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
id: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目id
|
||||||
|
*/
|
||||||
|
projectId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置名称
|
||||||
|
*/
|
||||||
|
configName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置地址
|
||||||
|
*/
|
||||||
|
configUrl: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DroneConfigForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目id
|
||||||
|
*/
|
||||||
|
projectId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置名称
|
||||||
|
*/
|
||||||
|
configName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置地址
|
||||||
|
*/
|
||||||
|
configUrl?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
remark?: string;
|
||||||
|
dockSocketUrl?: string;
|
||||||
|
aiUrl?: string;
|
||||||
|
srsUrl?: string;
|
||||||
|
rtmpPort?: string;
|
||||||
|
rtcPort?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DroneConfigQuery extends PageQuery {
|
||||||
|
/**
|
||||||
|
* 项目id
|
||||||
|
*/
|
||||||
|
projectId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置名称
|
||||||
|
*/
|
||||||
|
configName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置地址
|
||||||
|
*/
|
||||||
|
configUrl?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期范围参数
|
||||||
|
*/
|
||||||
|
params?: any;
|
||||||
|
}
|
||||||
@ -23,7 +23,7 @@ import { AttendanceMonthVO } from '../attendance/types';
|
|||||||
|
|
||||||
export const listConstructionMonth = (query?: ConstructionMonthQuery): AxiosPromise<AttendanceMonthVO[]> => {
|
export const listConstructionMonth = (query?: ConstructionMonthQuery): AxiosPromise<AttendanceMonthVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/list/attendance/month',
|
url: '/contractor/constructionUser/list/attendance/month',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -36,7 +36,7 @@ export const listConstructionMonth = (query?: ConstructionMonthQuery): AxiosProm
|
|||||||
|
|
||||||
export const listConstructionUser = (query?: ConstructionUserQuery): AxiosPromise<ConstructionUserVO[]> => {
|
export const listConstructionUser = (query?: ConstructionUserQuery): AxiosPromise<ConstructionUserVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/list',
|
url: '/contractor/constructionUser/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -48,7 +48,7 @@ export const listConstructionUser = (query?: ConstructionUserQuery): AxiosPromis
|
|||||||
*/
|
*/
|
||||||
export const getConstructionUser = (id: string | number): AxiosPromise<ConstructionUserVO> => {
|
export const getConstructionUser = (id: string | number): AxiosPromise<ConstructionUserVO> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/' + id,
|
url: '/contractor/constructionUser/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -59,7 +59,7 @@ export const getConstructionUser = (id: string | number): AxiosPromise<Construct
|
|||||||
*/
|
*/
|
||||||
export const transferConstructionUser = (data: skipType) => {
|
export const transferConstructionUser = (data: skipType) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/change/project',
|
url: '/contractor/constructionUser/change/project',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -81,7 +81,7 @@ export const getProjectContractorList = () => {
|
|||||||
*/
|
*/
|
||||||
export const addConstructionUser = (data: ConstructionUserForm): AxiosPromise<string | number> => {
|
export const addConstructionUser = (data: ConstructionUserForm): AxiosPromise<string | number> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser',
|
url: '/contractor/constructionUser',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -93,7 +93,7 @@ export const addConstructionUser = (data: ConstructionUserForm): AxiosPromise<st
|
|||||||
*/
|
*/
|
||||||
export const updateConstructionUser = (data: ConstructionUserForm) => {
|
export const updateConstructionUser = (data: ConstructionUserForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser',
|
url: '/contractor/constructionUser',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -105,7 +105,7 @@ export const updateConstructionUser = (data: ConstructionUserForm) => {
|
|||||||
*/
|
*/
|
||||||
export const delConstructionUser = (id: string | number | Array<string | number>) => {
|
export const delConstructionUser = (id: string | number | Array<string | number>) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/' + id,
|
url: '/contractor/constructionUser/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -116,7 +116,7 @@ export const delConstructionUser = (id: string | number | Array<string | number>
|
|||||||
*/
|
*/
|
||||||
export const updateConstructionUserStatus = (data: ConstructionUserStatusForm) => {
|
export const updateConstructionUserStatus = (data: ConstructionUserStatusForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/batch/status',
|
url: '/contractor/constructionUser/batch/status',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -128,7 +128,7 @@ export const updateConstructionUserStatus = (data: ConstructionUserStatusForm) =
|
|||||||
*/
|
*/
|
||||||
export const updateConstructionUserPlayCardStatus = (data: ConstructionUserPlayCardForm) => {
|
export const updateConstructionUserPlayCardStatus = (data: ConstructionUserPlayCardForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/batch/clock',
|
url: '/contractor/constructionUser/batch/clock',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -140,7 +140,7 @@ export const updateConstructionUserPlayCardStatus = (data: ConstructionUserPlayC
|
|||||||
*/
|
*/
|
||||||
export const updateConstructionUserPlayCardOneStatus = (data: ConstructionUserPlayCardForm) => {
|
export const updateConstructionUserPlayCardOneStatus = (data: ConstructionUserPlayCardForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/clock',
|
url: '/contractor/constructionUser/clock',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -152,7 +152,7 @@ export const updateConstructionUserPlayCardOneStatus = (data: ConstructionUserPl
|
|||||||
*/
|
*/
|
||||||
export const updateConstructionUserSalary = (data: ConstructionUserSalaryForm) => {
|
export const updateConstructionUserSalary = (data: ConstructionUserSalaryForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUser/salary',
|
url: '/contractor/constructionUser/salary',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -164,7 +164,7 @@ export const updateConstructionUserSalary = (data: ConstructionUserSalaryForm) =
|
|||||||
*/
|
*/
|
||||||
export const getConstructionUserExit = (query: ConstructionUserExitForm) => {
|
export const getConstructionUserExit = (query: ConstructionUserExitForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUserExit/list',
|
url: '/contractor/constructionUserExit/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -177,7 +177,7 @@ export const getConstructionUserExit = (query: ConstructionUserExitForm) => {
|
|||||||
export const dowloadConstructionUserTemplate = (query: ConstructionUserTemplateForm) => {
|
export const dowloadConstructionUserTemplate = (query: ConstructionUserTemplateForm) => {
|
||||||
let { projectId } = query;
|
let { projectId } = query;
|
||||||
const fileName = projectId + '_project.zip';
|
const fileName = projectId + '_project.zip';
|
||||||
return download('/project/constructionUserFile/exportFileTemplate', query, fileName);
|
return download('/contractor/constructionUserFile/exportFileTemplate', query, fileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,7 +186,7 @@ export const dowloadConstructionUserTemplate = (query: ConstructionUserTemplateF
|
|||||||
*/
|
*/
|
||||||
export const delConstructionUserMember = (data: ConstructionUserMembeForm) => {
|
export const delConstructionUserMember = (data: ConstructionUserMembeForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/projectTeamMember/',
|
url: '/contractor/projectTeamMember/',
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
@ -198,7 +198,7 @@ export const delConstructionUserMember = (data: ConstructionUserMembeForm) => {
|
|||||||
*/
|
*/
|
||||||
export const importConstructionUserInfo = (file: string) => {
|
export const importConstructionUserInfo = (file: string) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/constructionUserFile/upload/zip',
|
url: '/contractor/constructionUserFile/upload/zip',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: { file }
|
data: { file }
|
||||||
});
|
});
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { ContractorForm, ContractorQuery, ContractorVO } from '@/api/project/con
|
|||||||
|
|
||||||
export const listContractor = (query?: ContractorQuery): AxiosPromise<ContractorVO[]> => {
|
export const listContractor = (query?: ContractorQuery): AxiosPromise<ContractorVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractor/list',
|
url: '/contractor/contractor/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -22,7 +22,7 @@ export const listContractor = (query?: ContractorQuery): AxiosPromise<Contractor
|
|||||||
*/
|
*/
|
||||||
export const getContractor = (id: string | number): AxiosPromise<ContractorVO> => {
|
export const getContractor = (id: string | number): AxiosPromise<ContractorVO> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractor/' + id,
|
url: '/contractor/contractor/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -33,7 +33,7 @@ export const getContractor = (id: string | number): AxiosPromise<ContractorVO> =
|
|||||||
*/
|
*/
|
||||||
export const addContractor = (data: ContractorForm): AxiosPromise<string | number> => {
|
export const addContractor = (data: ContractorForm): AxiosPromise<string | number> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractor',
|
url: '/contractor/contractor',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -45,7 +45,7 @@ export const addContractor = (data: ContractorForm): AxiosPromise<string | numbe
|
|||||||
*/
|
*/
|
||||||
export const updateContractor = (data: ContractorForm) => {
|
export const updateContractor = (data: ContractorForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractor',
|
url: '/contractor/contractor',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -57,7 +57,7 @@ export const updateContractor = (data: ContractorForm) => {
|
|||||||
*/
|
*/
|
||||||
export const delContractor = (id: string | number | Array<string | number>) => {
|
export const delContractor = (id: string | number | Array<string | number>) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractor/' + id,
|
url: '/contractor/contractor/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
import { ContractorMaterialVO, ContractorMaterialForm, ContractorMaterialQuery } from '@/api/contractor/contractorMaterial/types';
|
import { ContractorMaterialVO, ContractorMaterialForm, ContractorMaterialQuery } from '@/api/project/contractorMaterial/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询分包方物料列表
|
* 查询分包方物料列表
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { ContractorToolVO, ContractorToolForm, ContractorToolQuery } from '@/api
|
|||||||
|
|
||||||
export const listContractorTool = (query?: ContractorToolQuery): AxiosPromise<ContractorToolVO[]> => {
|
export const listContractorTool = (query?: ContractorToolQuery): AxiosPromise<ContractorToolVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractorTool/list',
|
url: '/contractor/contractorTool/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -22,7 +22,7 @@ export const listContractorTool = (query?: ContractorToolQuery): AxiosPromise<Co
|
|||||||
*/
|
*/
|
||||||
export const getContractorTool = (id: string | number): AxiosPromise<ContractorToolVO> => {
|
export const getContractorTool = (id: string | number): AxiosPromise<ContractorToolVO> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractorTool/' + id,
|
url: '/contractor/contractorTool/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -33,7 +33,7 @@ export const getContractorTool = (id: string | number): AxiosPromise<ContractorT
|
|||||||
*/
|
*/
|
||||||
export const addContractorTool = (data: ContractorToolForm) => {
|
export const addContractorTool = (data: ContractorToolForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractorTool',
|
url: '/contractor/contractorTool',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -45,7 +45,7 @@ export const addContractorTool = (data: ContractorToolForm) => {
|
|||||||
*/
|
*/
|
||||||
export const updateContractorTool = (data: ContractorToolForm) => {
|
export const updateContractorTool = (data: ContractorToolForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractorTool',
|
url: '/contractor/contractorTool',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -57,7 +57,7 @@ export const updateContractorTool = (data: ContractorToolForm) => {
|
|||||||
*/
|
*/
|
||||||
export const delContractorTool = (id: string | number | Array<string | number>) => {
|
export const delContractorTool = (id: string | number | Array<string | number>) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/contractorTool/' + id,
|
url: '/contractor/contractorTool/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { SubcontractVO, SubcontractForm, SubcontractQuery } from '@/api/project/
|
|||||||
|
|
||||||
export const listSubcontract = (query?: SubcontractQuery): AxiosPromise<SubcontractVO[]> => {
|
export const listSubcontract = (query?: SubcontractQuery): AxiosPromise<SubcontractVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/subcontract/list',
|
url: '/contractor/subcontract/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -22,7 +22,7 @@ export const listSubcontract = (query?: SubcontractQuery): AxiosPromise<Subcontr
|
|||||||
*/
|
*/
|
||||||
export const getSubcontract = (id: string | number): AxiosPromise<SubcontractVO> => {
|
export const getSubcontract = (id: string | number): AxiosPromise<SubcontractVO> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/subcontract/' + id,
|
url: '/contractor/subcontract/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -33,7 +33,7 @@ export const getSubcontract = (id: string | number): AxiosPromise<SubcontractVO>
|
|||||||
*/
|
*/
|
||||||
export const addSubcontract = (data: SubcontractForm) => {
|
export const addSubcontract = (data: SubcontractForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/subcontract',
|
url: '/contractor/subcontract',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -45,7 +45,7 @@ export const addSubcontract = (data: SubcontractForm) => {
|
|||||||
*/
|
*/
|
||||||
export const updateSubcontract = (data: SubcontractForm) => {
|
export const updateSubcontract = (data: SubcontractForm) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/subcontract',
|
url: '/contractor/subcontract',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
@ -57,7 +57,7 @@ export const updateSubcontract = (data: SubcontractForm) => {
|
|||||||
*/
|
*/
|
||||||
export const delSubcontract = (id: string | number | Array<string | number>) => {
|
export const delSubcontract = (id: string | number | Array<string | number>) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/project/subcontract/' + id,
|
url: '/contractor/subcontract/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
63
src/api/safety/violationRecord/index.ts
Normal file
63
src/api/safety/violationRecord/index.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import { AxiosPromise } from 'axios';
|
||||||
|
import { ViolationRecordVO, ViolationRecordForm, ViolationRecordQuery } from '@/api/safety/violationRecord/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询违规记录列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listViolationRecord = (query?: ViolationRecordQuery): AxiosPromise<ViolationRecordVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/safety/violationRecord/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询违规记录详细
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getViolationRecord = (id: string | number): AxiosPromise<ViolationRecordVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/safety/violationRecord/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增违规处理人
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addViolationRecord = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/safety/violationRecord/handler',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改违规记录
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateViolationRecord = (data: ViolationRecordForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/safety/violationRecord',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除违规记录
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delViolationRecord = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/safety/violationRecord/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
241
src/api/safety/violationRecord/types.ts
Normal file
241
src/api/safety/violationRecord/types.ts
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
export interface ViolationRecordVO {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
id: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目id
|
||||||
|
*/
|
||||||
|
projectId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章等级id
|
||||||
|
*/
|
||||||
|
levelId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章类型
|
||||||
|
*/
|
||||||
|
violationType: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章时间
|
||||||
|
*/
|
||||||
|
violationTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章处理人id
|
||||||
|
*/
|
||||||
|
handlerId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整改措施
|
||||||
|
*/
|
||||||
|
measure: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整改时间
|
||||||
|
*/
|
||||||
|
rectificationTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查情况
|
||||||
|
*/
|
||||||
|
review: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查状态(1通过 2未通过)
|
||||||
|
*/
|
||||||
|
reviewType: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查时间
|
||||||
|
*/
|
||||||
|
reviewTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理流程类型(0仅通知 1通知整改复查)
|
||||||
|
*/
|
||||||
|
processType: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工单状态(1通知 2整改 3复查)
|
||||||
|
*/
|
||||||
|
status: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
remark: string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ViolationRecordForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目id
|
||||||
|
*/
|
||||||
|
projectId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章等级id
|
||||||
|
*/
|
||||||
|
levelId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别记录id
|
||||||
|
*/
|
||||||
|
recognizeId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章类型
|
||||||
|
*/
|
||||||
|
violationType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章时间
|
||||||
|
*/
|
||||||
|
violationTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章处理人id
|
||||||
|
*/
|
||||||
|
handlerId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理期限
|
||||||
|
*/
|
||||||
|
disposeDeadline?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理时间
|
||||||
|
*/
|
||||||
|
disposeTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整改措施
|
||||||
|
*/
|
||||||
|
measure?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整改时间
|
||||||
|
*/
|
||||||
|
rectificationTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查情况
|
||||||
|
*/
|
||||||
|
review?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查状态(1通过 2未通过)
|
||||||
|
*/
|
||||||
|
reviewType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查时间
|
||||||
|
*/
|
||||||
|
reviewTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理流程类型(0仅通知 1通知整改复查)
|
||||||
|
*/
|
||||||
|
processType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工单状态(1通知 2整改 3复查)
|
||||||
|
*/
|
||||||
|
status?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
remark?: string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ViolationRecordQuery extends PageQuery {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目id
|
||||||
|
*/
|
||||||
|
projectId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章类型
|
||||||
|
*/
|
||||||
|
violationType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章时间
|
||||||
|
*/
|
||||||
|
violationTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 违章处理人id
|
||||||
|
*/
|
||||||
|
handlerId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理期限
|
||||||
|
*/
|
||||||
|
disposeDeadline?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理时间
|
||||||
|
*/
|
||||||
|
disposeTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整改措施
|
||||||
|
*/
|
||||||
|
measure?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整改时间
|
||||||
|
*/
|
||||||
|
rectificationTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查情况
|
||||||
|
*/
|
||||||
|
review?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查状态(1通过 2未通过)
|
||||||
|
*/
|
||||||
|
reviewType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复查时间
|
||||||
|
*/
|
||||||
|
reviewTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理流程类型(0仅通知 1通知整改复查)
|
||||||
|
*/
|
||||||
|
processType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工单状态(1通知 2整改 3复查)
|
||||||
|
*/
|
||||||
|
status?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期范围参数
|
||||||
|
*/
|
||||||
|
params?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
import {DeptForm, DeptQuery, DeptTreeVO, DeptVO} from './types';
|
import { DeptForm, DeptQuery, DeptTreeVO, DeptVO } from './types';
|
||||||
|
|
||||||
// 查询部门列表
|
// 查询部门列表
|
||||||
export const listDept = (query?: DeptQuery) => {
|
export const listDept = (query?: DeptQuery) => {
|
||||||
@ -11,6 +11,24 @@ export const listDept = (query?: DeptQuery) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDeptList = () => {
|
||||||
|
return request({
|
||||||
|
url: '/project/project/listNoDept',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询分包单位
|
||||||
|
* @param projectId
|
||||||
|
*/
|
||||||
|
export const optionProjectSelect = (projectId: number | string): any => {
|
||||||
|
return request({
|
||||||
|
url: '/contractor/contractor/listNoDept/' + projectId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过deptIds查询部门
|
* 通过deptIds查询部门
|
||||||
* @param deptIds
|
* @param deptIds
|
||||||
|
|||||||
@ -5,6 +5,8 @@ export interface DeptQuery extends PageQuery {
|
|||||||
deptName?: string;
|
deptName?: string;
|
||||||
deptCategory?: string;
|
deptCategory?: string;
|
||||||
status?: number;
|
status?: number;
|
||||||
|
deptType?: string;
|
||||||
|
isShow?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,6 +18,9 @@ export interface DeptVO extends BaseEntity {
|
|||||||
parentId: number | string;
|
parentId: number | string;
|
||||||
children: DeptVO[];
|
children: DeptVO[];
|
||||||
deptId: number | string;
|
deptId: number | string;
|
||||||
|
contractorList: any[];
|
||||||
|
projectId: number | string;
|
||||||
|
projectList: any[];
|
||||||
deptName: string;
|
deptName: string;
|
||||||
deptCategory: string;
|
deptCategory: string;
|
||||||
orderNum: number;
|
orderNum: number;
|
||||||
@ -48,10 +53,15 @@ export interface DeptForm {
|
|||||||
parentId?: number | string;
|
parentId?: number | string;
|
||||||
children?: DeptForm[];
|
children?: DeptForm[];
|
||||||
deptId?: number | string;
|
deptId?: number | string;
|
||||||
|
projectId?: number | string;
|
||||||
|
contractorId?: number | string;
|
||||||
|
rowProjectId?: number | string;
|
||||||
deptName?: string;
|
deptName?: string;
|
||||||
deptCategory?: string;
|
deptCategory?: string;
|
||||||
orderNum?: number;
|
orderNum?: number;
|
||||||
leader?: string;
|
leader?: string;
|
||||||
|
deptType?: string;
|
||||||
|
isShow?: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
|
|||||||
@ -11,6 +11,14 @@ export function listPost(query: { pageNum: number; pageSize: number }): AxiosPro
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询岗位列表
|
||||||
|
export function listTreeByProject(projectId: string): AxiosPromise<PostVO[]> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/list/treeByProjectId/' + projectId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 查询岗位详细
|
// 查询岗位详细
|
||||||
export function getPost(postId: string | number): AxiosPromise<PostVO> {
|
export function getPost(postId: string | number): AxiosPromise<PostVO> {
|
||||||
return request({
|
return request({
|
||||||
@ -56,3 +64,14 @@ export function delPost(postId: string | number | (string | number)[]) {
|
|||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取岗位选择框列表
|
||||||
|
export function getRoleList(deptId?: number | string): AxiosPromise<any[]> {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/listNoPage',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
deptId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -6,7 +6,8 @@ export interface DeptTreeOption {
|
|||||||
label: string;
|
label: string;
|
||||||
parentId: string;
|
parentId: string;
|
||||||
weight: number;
|
weight: number;
|
||||||
children?: DeptTreeOption[];
|
children: DeptTreeOption[];
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoleDeptTree {
|
export interface RoleDeptTree {
|
||||||
@ -34,6 +35,7 @@ export interface RoleVO extends BaseEntity {
|
|||||||
export interface RoleQuery extends PageQuery {
|
export interface RoleQuery extends PageQuery {
|
||||||
roleName: string;
|
roleName: string;
|
||||||
roleKey: string;
|
roleKey: string;
|
||||||
|
deptId: string;
|
||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +48,9 @@ export interface RoleForm {
|
|||||||
deptCheckStrictly: boolean;
|
deptCheckStrictly: boolean;
|
||||||
remark: string;
|
remark: string;
|
||||||
dataScope?: string;
|
dataScope?: string;
|
||||||
|
isSpecial: string;
|
||||||
roleId: string | undefined;
|
roleId: string | undefined;
|
||||||
menuIds: Array<string | number>;
|
menuIds: Array<string | number>;
|
||||||
deptIds: Array<string | number>;
|
deptIds: Array<string | number>;
|
||||||
|
deptId?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -202,10 +202,11 @@ export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]
|
|||||||
/**
|
/**
|
||||||
* 查询部门下拉树结构
|
* 查询部门下拉树结构
|
||||||
*/
|
*/
|
||||||
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
|
export const deptTreeSelect = (data?: { isShow: string }): AxiosPromise<DeptTreeVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/user/deptTree',
|
url: '/system/user/deptTree',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
|
params: data
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ export interface FlowDefinitionQuery extends PageQuery {
|
|||||||
flowName?: string;
|
flowName?: string;
|
||||||
category: string | number;
|
category: string | number;
|
||||||
isPublish?: number;
|
isPublish?: number;
|
||||||
|
projectId: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FlowDefinitionVo {
|
export interface FlowDefinitionVo {
|
||||||
@ -23,6 +24,7 @@ export interface FlowDefinitionForm {
|
|||||||
flowCode: string;
|
flowCode: string;
|
||||||
category: string;
|
category: string;
|
||||||
formPath: string;
|
formPath: string;
|
||||||
|
projectId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface definitionXmlVO {
|
export interface definitionXmlVO {
|
||||||
|
|||||||
@ -2,9 +2,11 @@ import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
routerJump(routerJumpVo: RouterJumpVo, proxy) {
|
routerJump(routerJumpVo: RouterJumpVo, proxy) {
|
||||||
|
console.log(routerJumpVo.formPath);
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: routerJumpVo.formPath,
|
path: routerJumpVo.formPath ? '/' + routerJumpVo.formPath : routerJumpVo.formPath,
|
||||||
query: {
|
query: {
|
||||||
id: routerJumpVo.businessId,
|
id: routerJumpVo.businessId,
|
||||||
type: routerJumpVo.type,
|
type: routerJumpVo.type,
|
||||||
|
|||||||
12
src/main.ts
12
src/main.ts
@ -49,12 +49,12 @@ VXETable.config({
|
|||||||
|
|
||||||
//本地保存飞机配置
|
//本地保存飞机配置
|
||||||
import { setLocal } from './utils';
|
import { setLocal } from './utils';
|
||||||
setLocal('dockAir', 'http://192.168.110.24:9136');
|
setLocal('dockAir', 'http://58.17.134.85:9512');
|
||||||
setLocal('aiUrl', 'http://192.168.110.23:8000');
|
setLocal('aiUrl', 'http://58.17.134.85:9512');
|
||||||
setLocal('host', '192.168.110.199');
|
setLocal('host', '121.37.237.116');
|
||||||
setLocal('rtmpPort', '1935');
|
setLocal('rtmpPort', '28451');
|
||||||
setLocal('rtcPort', '1985');
|
setLocal('rtcPort', '28453');
|
||||||
setLocal('dockSocketUrl', 'ws://192.168.110.8:9136/websocket');
|
setLocal('dockSocketUrl', 'ws://58.17.134.85:9512/websocket');
|
||||||
|
|
||||||
// 修改 el-dialog 默认点击遮照为不关闭
|
// 修改 el-dialog 默认点击遮照为不关闭
|
||||||
/*import { ElDialog } from 'element-plus';
|
/*import { ElDialog } from 'element-plus';
|
||||||
|
|||||||
@ -7,39 +7,23 @@ import { Style, Stroke, Fill } from 'ol/style';
|
|||||||
import GeoJSON from 'ol/format/GeoJSON';
|
import GeoJSON from 'ol/format/GeoJSON';
|
||||||
import { polygon as turfPolygon, booleanIntersects } from '@turf/turf';
|
import { polygon as turfPolygon, booleanIntersects } from '@turf/turf';
|
||||||
import { toLonLat } from 'ol/proj';
|
import { toLonLat } from 'ol/proj';
|
||||||
import DragPan from 'ol/interaction/DragPan';
|
|
||||||
import MouseWheelZoom from 'ol/interaction/MouseWheelZoom';
|
|
||||||
|
|
||||||
export class LassoSelector {
|
export class LassoSelector {
|
||||||
private map: OLMap;
|
private map: OLMap;
|
||||||
private drawLayer: VectorLayer<VectorSource>;
|
private drawLayer: VectorLayer<VectorSource>;
|
||||||
private drawSource: VectorSource;
|
private drawSource: VectorSource;
|
||||||
private overlaySource: VectorSource;
|
private overlaySource: VectorSource; // 新增用于闭合多边形
|
||||||
private overlayLayer: VectorLayer<VectorSource>;
|
private overlayLayer: VectorLayer<VectorSource>;
|
||||||
private drawing = false;
|
private drawing = false;
|
||||||
private coordinates: [number, number][] = [];
|
private coordinates: [number, number][] = [];
|
||||||
private targetSource: VectorSource;
|
private targetSource: VectorSource;
|
||||||
private isShiftKeyDown = false;
|
private onSelectCallback: (selected: Feature[]) => void;
|
||||||
private onSelectCallback: (selected: Feature[], isInvert?: boolean) => void;
|
|
||||||
private dragPanInteraction: DragPan | null = null;
|
|
||||||
private mouseWheelZoomInteraction: MouseWheelZoom | null = null;
|
|
||||||
|
|
||||||
constructor(map: OLMap, targetSource: VectorSource, onSelect: (selected: Feature[], isInvert?: boolean) => void) {
|
constructor(map: OLMap, targetSource: VectorSource, onSelect: (selected: Feature[]) => void) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
this.targetSource = targetSource;
|
this.targetSource = targetSource;
|
||||||
this.onSelectCallback = onSelect;
|
this.onSelectCallback = onSelect;
|
||||||
|
|
||||||
// 找出拖动和滚轮缩放交互
|
|
||||||
this.dragPanInteraction = this.map
|
|
||||||
.getInteractions()
|
|
||||||
.getArray()
|
|
||||||
.find((interaction) => interaction instanceof DragPan) as DragPan;
|
|
||||||
|
|
||||||
this.mouseWheelZoomInteraction = this.map
|
|
||||||
.getInteractions()
|
|
||||||
.getArray()
|
|
||||||
.find((interaction) => interaction instanceof MouseWheelZoom) as MouseWheelZoom;
|
|
||||||
|
|
||||||
this.drawSource = new VectorSource();
|
this.drawSource = new VectorSource();
|
||||||
this.drawLayer = new VectorLayer({
|
this.drawLayer = new VectorLayer({
|
||||||
source: this.drawSource,
|
source: this.drawSource,
|
||||||
@ -52,6 +36,7 @@ export class LassoSelector {
|
|||||||
});
|
});
|
||||||
this.map.addLayer(this.drawLayer);
|
this.map.addLayer(this.drawLayer);
|
||||||
|
|
||||||
|
// 新增:闭合多边形图层(半透明填充)
|
||||||
this.overlaySource = new VectorSource();
|
this.overlaySource = new VectorSource();
|
||||||
this.overlayLayer = new VectorLayer({
|
this.overlayLayer = new VectorLayer({
|
||||||
source: this.overlaySource,
|
source: this.overlaySource,
|
||||||
@ -74,25 +59,17 @@ export class LassoSelector {
|
|||||||
// 禁用默认右键菜单
|
// 禁用默认右键菜单
|
||||||
this.map.getViewport().addEventListener('contextmenu', (e) => e.preventDefault());
|
this.map.getViewport().addEventListener('contextmenu', (e) => e.preventDefault());
|
||||||
|
|
||||||
// pointerdown 捕获左键按下
|
// 右键按下开始绘制
|
||||||
this.map.getViewport().addEventListener('pointerdown', (e) => {
|
this.map.getViewport().addEventListener('mousedown', (e) => {
|
||||||
if (e.button === 0 && !this.drawing) {
|
if (e.button === 2 && !this.drawing) {
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
this.isShiftKeyDown = e.shiftKey;
|
|
||||||
this.drawing = true;
|
this.drawing = true;
|
||||||
this.coordinates = [];
|
this.coordinates = [];
|
||||||
this.drawSource.clear();
|
this.drawSource.clear();
|
||||||
this.overlaySource.clear();
|
this.overlaySource.clear();
|
||||||
|
|
||||||
// 禁用拖动和缩放
|
|
||||||
if (this.dragPanInteraction) this.dragPanInteraction.setActive(false);
|
|
||||||
if (this.mouseWheelZoomInteraction) this.mouseWheelZoomInteraction.setActive(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// pointermove 画线
|
// 鼠标移动实时绘制线和闭合多边形
|
||||||
this.map.on('pointermove', (evt) => {
|
this.map.on('pointermove', (evt) => {
|
||||||
if (!this.drawing) return;
|
if (!this.drawing) return;
|
||||||
const coord = evt.coordinate as [number, number];
|
const coord = evt.coordinate as [number, number];
|
||||||
@ -101,30 +78,11 @@ export class LassoSelector {
|
|||||||
this.renderPolygon();
|
this.renderPolygon();
|
||||||
});
|
});
|
||||||
|
|
||||||
// pointerup 捕获左键抬起
|
// 右键抬起结束绘制并选中
|
||||||
this.map.getViewport().addEventListener('pointerup', (e) => {
|
this.map.getViewport().addEventListener('mouseup', (e) => {
|
||||||
if (e.button === 0 && this.drawing) {
|
if (e.button === 2 && this.drawing) {
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
this.drawing = false;
|
this.drawing = false;
|
||||||
this.handleDrawEnd();
|
this.handleDrawEnd();
|
||||||
|
|
||||||
// 恢复拖动和缩放
|
|
||||||
if (this.dragPanInteraction) this.dragPanInteraction.setActive(true);
|
|
||||||
if (this.mouseWheelZoomInteraction) this.mouseWheelZoomInteraction.setActive(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 防止拖动导致意外事件
|
|
||||||
this.map.getViewport().addEventListener('pointercancel', (e) => {
|
|
||||||
if (this.drawing) {
|
|
||||||
this.drawing = false;
|
|
||||||
this.drawSource.clear();
|
|
||||||
this.overlaySource.clear();
|
|
||||||
|
|
||||||
if (this.dragPanInteraction) this.dragPanInteraction.setActive(true);
|
|
||||||
if (this.mouseWheelZoomInteraction) this.mouseWheelZoomInteraction.setActive(true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -142,6 +100,7 @@ export class LassoSelector {
|
|||||||
this.overlaySource.clear();
|
this.overlaySource.clear();
|
||||||
if (this.coordinates.length < 3) return;
|
if (this.coordinates.length < 3) return;
|
||||||
|
|
||||||
|
// 闭合多边形坐标(首尾闭合)
|
||||||
const polygonCoords = [...this.coordinates, this.coordinates[0]];
|
const polygonCoords = [...this.coordinates, this.coordinates[0]];
|
||||||
const polygon = new Polygon([polygonCoords]);
|
const polygon = new Polygon([polygonCoords]);
|
||||||
const feature = new Feature({ geometry: polygon });
|
const feature = new Feature({ geometry: polygon });
|
||||||
@ -181,10 +140,7 @@ export class LassoSelector {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (selected.length) {
|
this.onSelectCallback(selected);
|
||||||
this.onSelectCallback(selected, this.isShiftKeyDown);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drawSource.clear();
|
this.drawSource.clear();
|
||||||
this.overlaySource.clear();
|
this.overlaySource.clear();
|
||||||
}
|
}
|
||||||
@ -192,5 +148,6 @@ export class LassoSelector {
|
|||||||
destroy() {
|
destroy() {
|
||||||
this.map.removeLayer(this.drawLayer);
|
this.map.removeLayer(this.drawLayer);
|
||||||
this.map.removeLayer(this.overlayLayer);
|
this.map.removeLayer(this.overlayLayer);
|
||||||
|
// 如有需要,解绑事件
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export const globalHeaders = () => {
|
|||||||
|
|
||||||
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
|
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
|
||||||
axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID;
|
axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID;
|
||||||
axios.defaults.headers['projectId'] = cache.local.getJSON('selectedProject').id;
|
axios.defaults.headers['isEncrypt'] = true;
|
||||||
|
|
||||||
// 创建 axios 实例
|
// 创建 axios 实例
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
@ -85,6 +85,8 @@ service.interceptors.request.use(
|
|||||||
// 生成一个 AES 密钥
|
// 生成一个 AES 密钥
|
||||||
const aesKey = generateAesKey();
|
const aesKey = generateAesKey();
|
||||||
config.headers[encryptHeader] = encrypt(encryptBase64(aesKey));
|
config.headers[encryptHeader] = encrypt(encryptBase64(aesKey));
|
||||||
|
console.log(encrypt(encryptBase64(aesKey)));
|
||||||
|
|
||||||
config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey);
|
config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -163,12 +163,11 @@ const handleSelectionChange = (selection: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDetail = async (row) => {
|
const handleDetail = async (row) => {
|
||||||
const res = await listByIds(row.attachments);
|
const res = await listByIds(row.id);
|
||||||
tableDetail.value = {
|
tableDetail.value = {
|
||||||
...row,
|
...row,
|
||||||
...res.data[0]
|
...res.data[0]
|
||||||
};
|
};
|
||||||
console.log('🚀 ~ handleDetail ~ tableDetail.value:', tableDetail.value);
|
|
||||||
detailVisible.value = true;
|
detailVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -12,65 +12,24 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" prop="bookName" label="卷册名称" />
|
<el-table-column align="center" prop="bookName" label="卷册名称" />
|
||||||
<el-table-column align="center" prop="bookNo" label="卷册号" />
|
<el-table-column align="center" prop="bookNo" label="卷册号" />
|
||||||
<!-- <el-table-column align="center" label="附图">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<ImagePreview :src="row.hasAttachment" disabled :width="80" />
|
|
||||||
</template>
|
|
||||||
</el-table-column> -->
|
|
||||||
<!-- <el-table-column align="center" prop="changeReasons" label="变更原因" width="100">
|
|
||||||
<template #default="{ row }">
|
|
||||||
{{ row.changeReasons?.join(', ') }}
|
|
||||||
</template>
|
|
||||||
</el-table-column> -->
|
|
||||||
<el-table-column align="center" prop="changeContent" label="变更内容" />
|
<el-table-column align="center" prop="changeContent" label="变更内容" />
|
||||||
<el-table-column align="center" prop="costEstimate" label="变更费用估算" />
|
<el-table-column align="center" prop="costEstimate" label="变更费用估算1" />
|
||||||
|
<el-table-column label="流程状态" align="center" prop="status">
|
||||||
<!-- <el-table-column label="施工承包单位" align="center">
|
|
||||||
<el-table-column align="center" prop="contractorManager" label="项目经理" width="100" />
|
|
||||||
<el-table-column align="center" prop="contractorDate" label="日期" width="130">
|
|
||||||
<template #default="{ row }">{{ formatDate(row.contractorDate) }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column label="总承包单位" align="center">
|
|
||||||
<el-table-column align="center" prop="generalTechLeader" label="项目技术负责人" width="150" />
|
|
||||||
<el-table-column align="center" prop="generalDate" label="日期" width="130">
|
|
||||||
<template #default="{ row }">{{ formatDate(row.generalDate) }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column label="设计单位" align="center">
|
|
||||||
<el-table-column align="center" prop="designer" label="设计代表" width="100" />
|
|
||||||
<el-table-column align="center" prop="designerDate" label="日期" width="130">
|
|
||||||
<template #default="{ row }">{{ formatDate(row.designerDate) }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column label="项目监理单位" align="center">
|
|
||||||
<el-table-column align="center" prop="supervisorEngineer" label="监理工程师" width="100" />
|
|
||||||
<el-table-column align="center" prop="chiefSupervisor" label="总监理工程师" width="110" />
|
|
||||||
<el-table-column align="center" prop="supervisorDate" label="日期" width="130">
|
|
||||||
<template #default="{ row }">{{ formatDate(row.supervisorDate) }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column label="建设单位" align="center">
|
|
||||||
<el-table-column align="center" prop="ownerLeader" label="负责人" />
|
|
||||||
<el-table-column align="center" prop="ownerDate" label="日期" width="130">
|
|
||||||
<template #default="{ row }">{{ formatDate(row.ownerDate) }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table-column> -->
|
|
||||||
|
|
||||||
<el-table-column align="center" prop="content" label="操作" width="160">
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" prop="content" label="操作" width="240">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="warning" v-if="scope.row.status === 'draft'" icon="Edit" @click="handleUpdate(scope.row)" class="ml-3"
|
||||||
|
>审批
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="primary" icon="View" @click="handleViewInfo(scope.row)" class="ml-3"> 查看流程 </el-button>
|
||||||
<el-button link type="success" icon="View" @click="handleDetail(scope.row)" class="ml-3"> 详情 </el-button>
|
<el-button link type="success" icon="View" @click="handleDetail(scope.row)" class="ml-3"> 详情 </el-button>
|
||||||
<!-- <el-button link type="primary" icon="Download" @click="handleDownload()"> 下载 </el-button> -->
|
|
||||||
<!-- <el-button link type="warning" icon="Edit" @click="handleDelete(scope.row)"> 修改 </el-button> -->
|
|
||||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"> 删除 </el-button>
|
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"> 删除 </el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 详情 -->
|
<!-- 详情 -->
|
||||||
<el-dialog title="变更单详情" v-model="detailVisible" width="1000">
|
<el-dialog title="变更单详情" v-model="detailVisible" width="1000">
|
||||||
<div class="w[850px] ma word-export-wrapper" ref="exportRef">
|
<div class="w[850px] ma word-export-wrapper" ref="exportRef">
|
||||||
@ -189,36 +148,16 @@
|
|||||||
import { listByIds } from '@/api/system/oss';
|
import { listByIds } from '@/api/system/oss';
|
||||||
import { dayjs } from 'element-plus';
|
import { dayjs } from 'element-plus';
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
const form = reactive({
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
projectName: '',
|
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||||
unitName: '',
|
|
||||||
profession: '',
|
|
||||||
applyDate: '2025-6-23 13:03:56',
|
|
||||||
bookName: '',
|
|
||||||
bookNo: '',
|
|
||||||
hasAttachment:
|
|
||||||
'http://58.17.134.85:9000/xinnengyuan-dev/doc/safety/knowledge/1897160897167638529/知识库/指导手册/2025-06-27_2f56bca1c4bc46c6b226858a18713c48.jpg', // 附图链接或图片地址
|
|
||||||
changeReasons: [0, 3, 5],
|
|
||||||
changeContent: '',
|
|
||||||
costEstimate: '',
|
|
||||||
|
|
||||||
contractorManager: '',
|
|
||||||
contractorDate: '',
|
|
||||||
generalTechLeader: '',
|
|
||||||
generalDate: '',
|
|
||||||
designer: '',
|
|
||||||
designerDate: '',
|
|
||||||
supervisorEngineer: '',
|
|
||||||
chiefSupervisor: '',
|
|
||||||
supervisorDate: '',
|
|
||||||
ownerLeader: '',
|
|
||||||
ownerDate: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const tableDetail = ref<any>({});
|
const tableDetail = ref<any>({});
|
||||||
@ -237,13 +176,11 @@ const detailVisible = ref(false);
|
|||||||
const formatDate = (val: string | Date) => (val ? dayjs(val).format('YYYY-MM-DD') : '');
|
const formatDate = (val: string | Date) => (val ? dayjs(val).format('YYYY-MM-DD') : '');
|
||||||
|
|
||||||
const handleDetail = async (row) => {
|
const handleDetail = async (row) => {
|
||||||
const res = await listByIds(row.hasAttachment);
|
const res = await listByIds(row.id);
|
||||||
tableDetail.value = {
|
tableDetail.value = {
|
||||||
...row,
|
...row,
|
||||||
hasAttachmentList: res.data
|
hasAttachmentList: res.data
|
||||||
};
|
};
|
||||||
console.log(tableDetail.value);
|
|
||||||
|
|
||||||
detailVisible.value = true;
|
detailVisible.value = true;
|
||||||
};
|
};
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
@ -254,7 +191,32 @@ const handleSelectionChange = (selection: any) => {
|
|||||||
const handleDelete = (row) => {
|
const handleDelete = (row) => {
|
||||||
emit('delete', row.id);
|
emit('delete', row.id);
|
||||||
};
|
};
|
||||||
|
const handleUpdate = (row) => {
|
||||||
|
// 添加审批
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/cory/template/indexEdit`,
|
||||||
|
query: {
|
||||||
|
thumbnailUrl: props.thumbnail,
|
||||||
|
row: JSON.stringify(row),
|
||||||
|
id: row.id,
|
||||||
|
type: 'update'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleViewInfo = (row) => {
|
||||||
|
// 添加审批
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/cory/template/indexEdit`,
|
||||||
|
query: {
|
||||||
|
thumbnailUrl: props.thumbnail,
|
||||||
|
row: JSON.stringify(row),
|
||||||
|
id: row.id,
|
||||||
|
type: 'view'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
const handleDownload = () => {
|
const handleDownload = () => {
|
||||||
const style = `
|
const style = `
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@ -1,75 +1,59 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<el-tabs type="border-card" v-model="activeName" @tab-click="handleClick">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-tab-pane label="变更单" name="1"
|
||||||
<el-card shadow="hover">
|
><el-card shadow="never">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<template #header>
|
||||||
<el-form-item label="模板类型" prop="projectType">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-select v-model="queryParams.projectType" placeholder="请选择模板类型" clearable filterable @change="selectType">
|
<el-col :span="1.5">
|
||||||
<el-option v-for="item in projectTypeOptions" :key="item.name" :label="item.name" :value="item.name"> </el-option>
|
<el-button type="primary" plain icon="Plus" :disabled="addSingle" @click="handleAddApp" v-hasPermi="['quality:qualityInspection:add']"
|
||||||
</el-select>
|
>上传变更单模版</el-button
|
||||||
</el-form-item>
|
>
|
||||||
<!-- <el-form-item>
|
</el-col>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
</el-row>
|
||||||
</el-form-item> -->
|
</template>
|
||||||
</el-form>
|
<EngineeringChangeApplicationForm
|
||||||
</el-card>
|
@selection-change="handleSelectionChange"
|
||||||
</div>
|
:data="tableData"
|
||||||
</transition>
|
:thumbnail="projectTypeOptions[1].thumbnail"
|
||||||
<el-card shadow="never">
|
@delete="handleDelete"
|
||||||
<template #header>
|
></EngineeringChangeApplicationForm>
|
||||||
<el-row :gutter="10" class="mb8">
|
<pagination
|
||||||
<el-col :span="1.5">
|
v-show="total > 0"
|
||||||
<el-button type="primary" plain icon="Plus" :disabled="addSingle" @click="handleAdd" v-hasPermi="['quality:qualityInspection:add']"
|
:total="total"
|
||||||
>新增</el-button
|
v-model:page="queryParams.pageNum"
|
||||||
>
|
v-model:limit="queryParams.pageSize"
|
||||||
</el-col>
|
@pagination="getList"
|
||||||
<!-- <el-col :span="1.5">
|
/> </el-card
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['quality:qualityInspection:edit']"
|
></el-tab-pane>
|
||||||
>修改</el-button
|
<el-tab-pane label="外部联系单" name="0"
|
||||||
>
|
><el-card shadow="never">
|
||||||
</el-col> -->
|
<template #header>
|
||||||
<el-col :span="1.5">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-button
|
<el-col :span="1.5">
|
||||||
type="danger"
|
<el-button type="primary" plain icon="Plus" :disabled="addSingle" @click="handleAdd" v-hasPermi="['quality:qualityInspection:add']"
|
||||||
plain
|
>上传外部联系单模版</el-button
|
||||||
icon="Delete"
|
>
|
||||||
:disabled="multiple"
|
</el-col>
|
||||||
@click="handleDelete()"
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
v-hasPermi="['quality:qualityInspection:remove']"
|
</el-row>
|
||||||
>删除</el-button
|
</template>
|
||||||
>
|
<Contactform @selection-change="handleSelectionChange" :data="tableData" @delete="handleDelete"></Contactform>
|
||||||
</el-col>
|
<pagination
|
||||||
<!-- <el-col :span="1.5">
|
v-show="total > 0"
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['quality:qualityInspection:export']">导出</el-button>
|
:total="total"
|
||||||
</el-col> -->
|
v-model:page="queryParams.pageNum"
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
v-model:limit="queryParams.pageSize"
|
||||||
</el-row>
|
@pagination="getList"
|
||||||
</template>
|
/> </el-card
|
||||||
<!-- card body -->
|
></el-tab-pane>
|
||||||
<Contactform
|
</el-tabs>
|
||||||
v-if="queryParams.projectType == '外部联系单'"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
:data="tableData"
|
|
||||||
@delete="handleDelete"
|
|
||||||
></Contactform>
|
|
||||||
<EngineeringChangeApplicationForm
|
|
||||||
v-if="queryParams.projectType == '变更单'"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
:data="tableData"
|
|
||||||
@delete="handleDelete"
|
|
||||||
></EngineeringChangeApplicationForm>
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<el-dialog title="新增模板" v-model="dialogVisible" width="800">
|
<el-dialog title="新增模板" v-model="dialogVisible" width="800">
|
||||||
<el-form :model="form" :rules="rules" ref="formRef" label-width="110px">
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="110px">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<!-- <img :src="thumbnailUrl" alt="" style="width: 150px;" /> -->
|
|
||||||
<div><image-preview :src="thumbnailUrl" width="150px"></image-preview></div>
|
<div><image-preview :src="thumbnailUrl" width="150px"></image-preview></div>
|
||||||
|
<div>
|
||||||
<div v-if="queryParams.projectType == '外部联系单'">
|
|
||||||
<el-form-item label="工程名称" prop="projectName">
|
<el-form-item label="工程名称" prop="projectName">
|
||||||
<el-input v-model="form.projectName" placeholder="请输入工程名称" />
|
<el-input v-model="form.projectName" placeholder="请输入工程名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -111,94 +95,6 @@
|
|||||||
<el-date-picker v-model="form.ownerDate" type="date" placeholder="选择日期" style="width: 100%" />
|
<el-date-picker v-model="form.ownerDate" type="date" placeholder="选择日期" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="queryParams.projectType === '变更单'">
|
|
||||||
<el-form-item label="工程名称">
|
|
||||||
<el-input v-model="form.projectName" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="提出单位">
|
|
||||||
<el-input v-model="form.unitName" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="专业">
|
|
||||||
<el-input v-model="form.profession" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="提出日期">
|
|
||||||
<el-date-picker v-model="form.applyDate" type="date" placeholder="选择日期" style="width: 100%" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="卷册名称">
|
|
||||||
<el-input v-model="form.bookName" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="卷册号">
|
|
||||||
<el-input v-model="form.bookNo" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="附图">
|
|
||||||
<image-upload v-model="form.hasAttachment"></image-upload>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="变更原因">
|
|
||||||
<el-checkbox-group v-model="form.changeReasons">
|
|
||||||
<el-checkbox label="设计漏项" class="w45%" />
|
|
||||||
<el-checkbox label="设计改进" />
|
|
||||||
<el-checkbox label="设计差错" class="w45%" />
|
|
||||||
<el-checkbox label="接口差错" />
|
|
||||||
<el-checkbox label="业主要求" class="w45%" />
|
|
||||||
<el-checkbox label="施工承包商要求" />
|
|
||||||
<el-checkbox label="外部资料不符" class="w45%" />
|
|
||||||
<el-checkbox label="材料代用或其他" />
|
|
||||||
</el-checkbox-group>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="变更内容">
|
|
||||||
<el-input v-model="form.changeContent" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="变更费用估算">
|
|
||||||
<el-input v-model="form.costEstimate" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-divider class="mb-10! mt-10!">施工承包单位</el-divider>
|
|
||||||
<el-form-item label="项目经理" prop="asupervisorLeader">
|
|
||||||
<el-input v-model="form.asupervisorLeader" placeholder="请输入项目经理姓名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="日期" prop="asupervisorDate">
|
|
||||||
<el-date-picker v-model="form.asupervisorDate" type="date" placeholder="选择日期" style="width: 100%" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-divider class="mb-10! mt-10!">总承包单位</el-divider>
|
|
||||||
<el-form-item label="项目技术负责人" prop="bsupervisorLeader">
|
|
||||||
<el-input v-model="form.bsupervisorLeader" placeholder="请输入项目技术负责人姓名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="日期" prop="bsupervisorDate">
|
|
||||||
<el-date-picker v-model="form.bsupervisorDate" type="date" placeholder="选择日期" style="width: 100%" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-divider class="mb-10! mt-10!">设计单位</el-divider>
|
|
||||||
<el-form-item label="设计代表" prop="csupervisorLeader">
|
|
||||||
<el-input v-model="form.csupervisorLeader" placeholder="请输入设计代表姓名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="日期" prop="csupervisorDate">
|
|
||||||
<el-date-picker v-model="form.csupervisorDate" type="date" placeholder="选择日期" style="width: 100%" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-divider class="mb-10! mt-10!">项目监理单位</el-divider>
|
|
||||||
<el-form-item label="监理工程师" prop="dsupervisorLeader">
|
|
||||||
<el-input v-model="form.dsupervisorLeader" placeholder="请输入监理工程师姓名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="总监理工程师" prop="dasupervisorLeader">
|
|
||||||
<el-input v-model="form.dasupervisorLeader" placeholder="请输入总监理工程师姓名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="日期" prop="dsupervisorDate">
|
|
||||||
<el-date-picker v-model="form.dsupervisorDate" type="date" placeholder="选择日期" style="width: 100%" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-divider class="mb-10! mt-10!">建设单位</el-divider>
|
|
||||||
<el-form-item label="负责人" prop="esupervisorLeader">
|
|
||||||
<el-input v-model="form.esupervisorLeader" placeholder="请输入负责人姓名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="日期" prop="esupervisorDate">
|
|
||||||
<el-date-picker v-model="form.esupervisorDate" type="date" placeholder="选择日期" style="width: 100%" />
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -224,15 +120,10 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
// 从 store 中获取项目列表和当前选中的项目
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
const { safety_inspection_violation_type, safety_inspection_check_type } = toRefs<any>(
|
|
||||||
proxy?.useDict('safety_inspection_violation_type', 'safety_inspection_check_type')
|
|
||||||
);
|
|
||||||
const teamOpt = ref([]);
|
|
||||||
const foremanOpt = ref([]);
|
|
||||||
const thumbnailUrl = ref('');
|
const thumbnailUrl = ref('');
|
||||||
const tableData = ref([]);
|
const tableData = ref([]);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
|
const activeName = ref('1');
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const dialogVisible = ref<boolean>(false);
|
const dialogVisible = ref<boolean>(false);
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
@ -338,17 +229,6 @@ const handleAdd = () => {
|
|||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeForeman = (value: string | number) => {
|
|
||||||
// const team = teamList.value.filter((team) => team.id === value)[0];
|
|
||||||
// foremanOpt.value = team.foremanList?.map((foreman: foremanQuery) => ({
|
|
||||||
// label: foreman.foremanName,
|
|
||||||
// value: foreman.foremanId
|
|
||||||
// }));
|
|
||||||
// form.value.correctorId = '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleQuery = () => {};
|
|
||||||
const resetQuery = () => {};
|
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
if (!queryParams.value.projectType) {
|
if (!queryParams.value.projectType) {
|
||||||
const res = await listContactTypeformtemplate(queryParams.value);
|
const res = await listContactTypeformtemplate(queryParams.value);
|
||||||
@ -376,8 +256,6 @@ const handleDelete = async (id?: string) => {
|
|||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleUpdate = () => {};
|
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: any) => {
|
const handleSelectionChange = (selection: any) => {
|
||||||
ids.value = selection.map((item) => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
@ -392,10 +270,23 @@ const selectType = (value: string) => {
|
|||||||
getList();
|
getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetForm = () => {
|
const handleClick = (val) => {
|
||||||
formRef.value?.resetFields();
|
console.log(val);
|
||||||
|
queryParams.value.projectType = val.props.name;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
const handleAddApp = (row) => {
|
||||||
|
// 添加审批
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/relation-management/changeContact/indexEdit`,
|
||||||
|
query: {
|
||||||
|
thumbnailUrl: projectTypeOptions.value[1].thumbnail,
|
||||||
|
row,
|
||||||
|
type: 'add'
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
|||||||
442
src/views/cory/template/indexEdit.vue
Normal file
442
src/views/cory/template/indexEdit.vue
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-4 bg-gray-50">
|
||||||
|
<div class="max-w-4xl mx-auto">
|
||||||
|
<!-- 顶部按钮区域 -->
|
||||||
|
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||||
|
<approvalButton
|
||||||
|
@submitForm="submitForm"
|
||||||
|
@approvalVerifyOpen="approvalVerifyOpen"
|
||||||
|
@handleApprovalRecord="handleApprovalRecord"
|
||||||
|
:buttonLoading="buttonLoading"
|
||||||
|
:id="form.id"
|
||||||
|
:status="form.status"
|
||||||
|
:pageType="routeParams.type"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 表单区域 -->
|
||||||
|
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||||
|
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800">变更联系单</h3>
|
||||||
|
</div>
|
||||||
|
<div class="p-6">
|
||||||
|
<el-form
|
||||||
|
ref="leaveFormRef"
|
||||||
|
v-loading="loading"
|
||||||
|
:disabled="routeParams.type === 'view'"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="100px"
|
||||||
|
class="space-y-4"
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-1 gap-4">
|
||||||
|
<div class="flex">
|
||||||
|
<div><image-preview :src="thumbnailUrl" width="150px"></image-preview></div>
|
||||||
|
<div>
|
||||||
|
<el-form-item label="工程名称" prop="projectName">
|
||||||
|
<el-input v-model="form.projectName" placeholder="请输入工程名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="编号" prop="serialNumber">
|
||||||
|
<el-input v-model="form.serialNumber" placeholder="请输入编号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="致" prop="to">
|
||||||
|
<el-input v-model="form.to" placeholder="致:" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="主题" prop="subject">
|
||||||
|
<el-input v-model="form.subject" placeholder="请输入主题" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="内容" prop="content">
|
||||||
|
<el-input v-model="form.content" type="textarea" :rows="6" placeholder="请输入内容" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="附件" prop="attachments">
|
||||||
|
<file-upload v-model="form.attachments" :limit="1" :file-type="['pdf', 'png', 'jpg', 'jpeg', 'gif', 'bmp']"></file-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-divider class="mb-10! mt-10!">施工项目部</el-divider>
|
||||||
|
<el-form-item label="项目负责人" prop="contractorLeader">
|
||||||
|
<el-input v-model="form.contractorLeader" placeholder="请输入负责人姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="日期" prop="contractorDate">
|
||||||
|
<el-date-picker v-model="form.contractorDate" type="date" placeholder="选择日期" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-divider class="mb-10! mt-10!">项目监理机构</el-divider>
|
||||||
|
<el-form-item label="总监理工程师" prop="supervisorLeader">
|
||||||
|
<el-input v-model="form.supervisorLeader" placeholder="请输入总监理工程师姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="日期" prop="supervisorDate">
|
||||||
|
<el-date-picker v-model="form.supervisorDate" type="date" placeholder="选择日期" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-divider class="mb-10! mt-10!">建设单位</el-divider>
|
||||||
|
<el-form-item label="业主代表" prop="ownerRep">
|
||||||
|
<el-input v-model="form.ownerRep" placeholder="请输入业主代表" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="日期" prop="ownerDate">
|
||||||
|
<el-date-picker v-model="form.ownerDate" type="date" placeholder="选择日期" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<!-- 提交组件 -->
|
||||||
|
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||||
|
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||||
|
<!-- 流程选择对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
draggable
|
||||||
|
v-model="dialogVisible.visible"
|
||||||
|
:title="dialogVisible.title"
|
||||||
|
:before-close="handleClose"
|
||||||
|
width="500"
|
||||||
|
class="rounded-lg shadow-lg"
|
||||||
|
>
|
||||||
|
<div class="p-4">
|
||||||
|
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||||
|
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||||
|
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||||
|
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||||
|
>取消</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||||
|
>确认</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Leave" lang="ts">
|
||||||
|
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||||
|
import { startWorkFlow } from '@/api/workflow/task';
|
||||||
|
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||||
|
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||||
|
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||||
|
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { listByIds } from '@/api/system/oss';
|
||||||
|
import { addContactnotice,getContactnotice ,updateContactnotice} from '@/api/cory/contactnotice';
|
||||||
|
|
||||||
|
// 获取用户 store
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const loading = ref(true);
|
||||||
|
const thumbnailUrl = ref('');
|
||||||
|
//路由参数
|
||||||
|
const routeParams = ref<Record<string, any>>({});
|
||||||
|
const flowCodeOptions = [
|
||||||
|
{
|
||||||
|
value: currentProject.value?.id + '_changecontact',
|
||||||
|
label: '变更联系单审批'
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const flowCode = ref<string>('');
|
||||||
|
const status = ref<string>('');
|
||||||
|
const dialogVisible = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: '流程定义'
|
||||||
|
});
|
||||||
|
//提交组件
|
||||||
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||||
|
//审批记录组件
|
||||||
|
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||||
|
const leaveFormRef = ref<ElFormInstance>();
|
||||||
|
const dialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: '',
|
||||||
|
isEdit: false
|
||||||
|
});
|
||||||
|
const submitFormData = ref<StartProcessBo>({
|
||||||
|
businessId: '',
|
||||||
|
flowCode: '',
|
||||||
|
variables: {}
|
||||||
|
});
|
||||||
|
const taskVariables = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
const initFormData = {
|
||||||
|
id: undefined,
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
projectType: '',
|
||||||
|
projectName: '',
|
||||||
|
serialNumber: '',
|
||||||
|
to: '',
|
||||||
|
subject: '',
|
||||||
|
content: '',
|
||||||
|
attachments: '',
|
||||||
|
contractorLeader: '',
|
||||||
|
contractorDate: '',
|
||||||
|
supervisorLeader: '',
|
||||||
|
supervisorDate: '',
|
||||||
|
ownerRep: '',
|
||||||
|
ownerDate: '',
|
||||||
|
unitName: '',
|
||||||
|
profession: '',
|
||||||
|
applyDate: '',
|
||||||
|
bookName: '',
|
||||||
|
bookNo: '',
|
||||||
|
hasAttachment: '',
|
||||||
|
changeReasons: [],
|
||||||
|
changeContent: '',
|
||||||
|
costEstimate: '',
|
||||||
|
status: ''
|
||||||
|
};
|
||||||
|
const data = reactive({
|
||||||
|
form: { ...initFormData },
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
fileName: undefined,
|
||||||
|
fileType: undefined,
|
||||||
|
fileSuffix: undefined,
|
||||||
|
fileStatus: undefined,
|
||||||
|
originalName: undefined,
|
||||||
|
newest: undefined,
|
||||||
|
params: {}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
projectName: [{ required: true, message: '请输入工程名称', trigger: 'blur' }],
|
||||||
|
projectType: [{ required: true, message: '请选择模板类型', trigger: 'blur' }],
|
||||||
|
serialNumber: [{ required: true, message: '请输入编号', trigger: 'blur' }],
|
||||||
|
to: [{ required: true, message: '请输入接收方', trigger: 'blur' }],
|
||||||
|
subject: [{ required: true, message: '请输入主题', trigger: 'blur' }],
|
||||||
|
content: [{ required: true, message: '请输入内容', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.visible = false;
|
||||||
|
flowCode.value = '';
|
||||||
|
buttonLoading.value = false;
|
||||||
|
};
|
||||||
|
const { form, rules } = toRefs(data);
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = { ...initFormData };
|
||||||
|
leaveFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取详情 */
|
||||||
|
const getInfo = () => {
|
||||||
|
loading.value = true;
|
||||||
|
buttonLoading.value = false;
|
||||||
|
nextTick(async () => {
|
||||||
|
const res = await getContactnotice(routeParams.value.id);
|
||||||
|
var data = {
|
||||||
|
...JSON.parse(routeParams.value.row),
|
||||||
|
...JSON.parse(res.data.detail)
|
||||||
|
};
|
||||||
|
console.log(routeParams.value);
|
||||||
|
|
||||||
|
Object.assign(form.value, data);
|
||||||
|
loading.value = false;
|
||||||
|
buttonLoading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = (status1: string) => {
|
||||||
|
status.value = status1;
|
||||||
|
leaveFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true;
|
||||||
|
// var res;
|
||||||
|
// if (form.value.id) {
|
||||||
|
// res = await updateContactnotice(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
// } else {
|
||||||
|
// res = await addContactnotice(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
// }
|
||||||
|
// if (res.code == 200) {
|
||||||
|
dialog.visible = false;
|
||||||
|
submit(status.value, form.value);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitFlow = async () => {
|
||||||
|
handleStartWorkFlow(form.value);
|
||||||
|
dialogVisible.visible = false;
|
||||||
|
};
|
||||||
|
//提交申请
|
||||||
|
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||||
|
try {
|
||||||
|
submitFormData.value.flowCode = flowCode.value;
|
||||||
|
submitFormData.value.businessId = data.id;
|
||||||
|
//流程变量
|
||||||
|
taskVariables.value = {
|
||||||
|
// leave4/5 使用的流程变量
|
||||||
|
userList: ['1', '3', '4']
|
||||||
|
};
|
||||||
|
submitFormData.value.variables = taskVariables.value;
|
||||||
|
const resp = await startWorkFlow(submitFormData.value);
|
||||||
|
if (submitVerifyRef.value) {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//审批记录
|
||||||
|
const handleApprovalRecord = () => {
|
||||||
|
approvalRecordRef.value.init(form.value.id);
|
||||||
|
};
|
||||||
|
//提交回调
|
||||||
|
const submitCallback = async () => {
|
||||||
|
await proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.go(-1);
|
||||||
|
};
|
||||||
|
//审批
|
||||||
|
const approvalVerifyOpen = async () => {
|
||||||
|
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||||
|
};
|
||||||
|
// 图纸上传成功之后 开始提交
|
||||||
|
const submit = async (status, data) => {
|
||||||
|
form.value = data;
|
||||||
|
if (status === 'draft') {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
proxy?.$modal.msgSuccess('暂存成功');
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.go(-1);
|
||||||
|
} else {
|
||||||
|
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||||
|
flowCode.value = flowCodeOptions[0].value;
|
||||||
|
dialogVisible.visible = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//说明启动过先随意穿个参数
|
||||||
|
if (flowCode.value === '' || flowCode.value === null) {
|
||||||
|
flowCode.value = 'xx';
|
||||||
|
}
|
||||||
|
console.log(data);
|
||||||
|
await handleStartWorkFlow(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(async () => {
|
||||||
|
routeParams.value = proxy.$route.query;
|
||||||
|
thumbnailUrl.value = proxy.$route.query.thumbnailUrl;
|
||||||
|
reset();
|
||||||
|
loading.value = false;
|
||||||
|
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||||
|
getInfo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
/* 全局样式 */
|
||||||
|
:root {
|
||||||
|
--primary: #409eff;
|
||||||
|
--primary-light: #66b1ff;
|
||||||
|
--primary-dark: #3a8ee6;
|
||||||
|
--success: #67c23a;
|
||||||
|
--warning: #e6a23c;
|
||||||
|
--danger: #f56c6c;
|
||||||
|
--info: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单样式优化 */
|
||||||
|
.el-form-item {
|
||||||
|
.el-form-item__label {
|
||||||
|
color: #606266;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__inner,
|
||||||
|
.el-select .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s,
|
||||||
|
box-shadow 0.2s;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s,
|
||||||
|
box-shadow 0.2s;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮样式优化 */
|
||||||
|
.el-button {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&.is-primary {
|
||||||
|
background-color: var(--primary);
|
||||||
|
border-color: var(--primary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--primary-light);
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--primary-dark);
|
||||||
|
border-color: var(--primary-dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-text {
|
||||||
|
color: var(--primary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--primary-light);
|
||||||
|
background-color: rgba(64, 158, 255, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片样式优化 */
|
||||||
|
.el-card {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
/* transform: translateY(-2px); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 对话框样式优化 */
|
||||||
|
.el-dialog {
|
||||||
|
.el-dialog__header {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
padding: 15px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__footer {
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -306,7 +306,19 @@ const selectType = (value: string) => {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
formRef.value?.resetFields();
|
formRef.value?.resetFields();
|
||||||
};
|
};
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
form.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16,15 +16,16 @@
|
|||||||
<el-form-item label="专业" prop="specialty">
|
<el-form-item label="专业" prop="specialty">
|
||||||
<el-input v-model="queryParams.specialty" placeholder="请输入专业" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.specialty" placeholder="请输入专业" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="提出日期" prop="submitDate">
|
|
||||||
<el-date-picker clearable v-model="queryParams.submitDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择提出日期" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="卷册名称" prop="volumeName">
|
<el-form-item label="卷册名称" prop="volumeName">
|
||||||
<el-input v-model="queryParams.volumeName" placeholder="请输入卷册名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.volumeName" placeholder="请输入卷册名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="卷册号" prop="volumeNo">
|
<el-form-item label="卷册号" prop="volumeNo">
|
||||||
<el-input v-model="queryParams.volumeNo" placeholder="请输入卷册号" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.volumeNo" placeholder="请输入卷册号" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="提出日期" prop="submitDate">
|
||||||
|
<el-date-picker clearable v-model="queryParams.submitDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择提出日期" />
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
@ -38,12 +39,7 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:designChange:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:designChange:add']">上传设计变更</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['design:designChange:remove']"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -68,16 +64,26 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="变更内容" align="center" prop="changeContent" />
|
<el-table-column label="变更内容" align="center" prop="changeContent" />
|
||||||
<!-- <el-table-column label="变更费用估算" align="center" prop="costEstimation" /> -->
|
<!-- <el-table-column label="变更费用估算" align="center" prop="costEstimation" /> -->
|
||||||
<el-table-column label="变更文件" align="center" prop="fileId">
|
<el-table-column label="变更文件" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span style="color: rgb(41 145 255);cursor: pointer" @click="onOpen(scope.row.file.url)"> {{ scope.row.file.originalName }}</span>
|
<span v-if="scope.row.file" style="color: rgb(41 145 255); cursor: pointer" @click="onOpen(scope.row.file.url)">
|
||||||
|
{{ scope.row.file.originalName }}</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="流程状态" align="center" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="备注" align="center" prop="remark" />
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="查看" placement="top">
|
<el-tooltip content="查看流程" placement="top">
|
||||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)"></el-button>
|
<el-button link type="primary" icon="View" @click="handleViewInfo(scope.row)"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="查看文档" placement="top">
|
||||||
|
<el-button link type="primary" icon="Document" @click="handleView(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:designChange:edit']"></el-button>
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:designChange:edit']"></el-button>
|
||||||
@ -90,91 +96,13 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-dialog
|
|
||||||
:title="dialog.title"
|
|
||||||
v-model="dialog.visible"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
:close-on-press-escape="false"
|
|
||||||
width="800px"
|
|
||||||
append-to-body
|
|
||||||
>
|
|
||||||
<el-form ref="designChangeFormRef" :model="form" :rules="rules" label-width="110px">
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="申请单编号" prop="formNo">
|
|
||||||
<el-input v-model="form.formNo" placeholder="请输入申请单编号" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="工程名称" prop="projectName"> <el-input v-model="form.projectName" placeholder="请输入工程名称" /> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="提出单位" prop="submitUnit">
|
|
||||||
<el-input v-model="form.submitUnit" placeholder="请输入提出单位" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="专业" prop="specialty">
|
|
||||||
<el-input v-model="form.specialty" placeholder="请输入专业" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="提出日期" prop="submitDate">
|
|
||||||
<el-date-picker clearable v-model="form.submitDate" type="date" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择提出日期">
|
|
||||||
</el-date-picker> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="卷册名称" prop="volumeName"> <el-input v-model="form.volumeName" placeholder="请输入卷册名称" /> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="卷册号" prop="volumeNo"> <el-input v-model="form.volumeNo" placeholder="请输入卷册号" /> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="附图" prop="attachmentPic"> <image-upload v-model="form.attachmentPic" :fileSize="100" /> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="变更原因" prop="changeReason">
|
|
||||||
<el-checkbox-group v-model="form.changeReason">
|
|
||||||
<el-checkbox v-for="dict in design_change_reason_type" :key="dict.value" :label="dict.value">
|
|
||||||
{{ dict.label }}
|
|
||||||
</el-checkbox>
|
|
||||||
</el-checkbox-group>
|
|
||||||
</el-form-item></el-col
|
|
||||||
>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="变更内容" prop="changeContent">
|
|
||||||
<el-input v-model="form.changeContent" type="textarea" placeholder="请输入内容" /> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
<!-- <el-col :span="12">
|
|
||||||
<el-form-item label="变更费用估算" prop="costEstimation">
|
|
||||||
<el-input v-model="form.costEstimation" type="textarea" placeholder="请输入内容" /> </el-form-item
|
|
||||||
></el-col> -->
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="变更费用估算表" label-width="110px" prop="costEstimationFile">
|
|
||||||
<file-upload v-model="form.costEstimationFile" :fileSize="100" /> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="变更文件" prop="fileId"> <file-upload v-model="form.fileId" :fileSize="100" /> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
<el-col :span="24"
|
|
||||||
><el-form-item label="备注" prop="remark"> <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> </el-form-item
|
|
||||||
></el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<div class="dialog-footer">
|
|
||||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
|
||||||
<el-button @click="cancel">取 消</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
<wordDetial ref="wordDetialRef"></wordDetial>
|
<wordDetial ref="wordDetialRef"></wordDetial>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="DesignChange" lang="ts">
|
<script setup name="DesignChange" lang="ts">
|
||||||
import { listDesignChange, getDesignChange, delDesignChange, addDesignChange, updateDesignChange } from '@/api/design/designChange';
|
import { listDesignChange, delDesignChange } from '@/api/design/designChange';
|
||||||
import { DesignChangeVO, DesignChangeQuery, DesignChangeForm } from '@/api/design/designChange/types';
|
import { DesignChangeVO } from '@/api/design/designChange/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import wordDetial from '@/components/wordDetial/index';
|
import wordDetial from '@/components/wordDetial/index';
|
||||||
|
|
||||||
@ -185,7 +113,6 @@ const userStore = useUserStoreHook();
|
|||||||
// 从 store 中获取项目列表和当前选中的项目
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
const designChangeList = ref<DesignChangeVO[]>([]);
|
const designChangeList = ref<DesignChangeVO[]>([]);
|
||||||
const buttonLoading = ref(false);
|
|
||||||
const wordDetialRef = ref<InstanceType<typeof wordDetial>>();
|
const wordDetialRef = ref<InstanceType<typeof wordDetial>>();
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
@ -193,36 +120,9 @@ const ids = ref<Array<string | number>>([]);
|
|||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
|
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const designChangeFormRef = ref<ElFormInstance>();
|
const data = reactive({
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
|
||||||
visible: false,
|
|
||||||
title: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const initFormData: DesignChangeForm = {
|
|
||||||
id: undefined,
|
|
||||||
projectId: currentProject.value?.id,
|
|
||||||
formNo: undefined,
|
|
||||||
projectName: undefined,
|
|
||||||
submitUnit: undefined,
|
|
||||||
specialty: undefined,
|
|
||||||
submitDate: undefined,
|
|
||||||
volumeName: undefined,
|
|
||||||
volumeNo: undefined,
|
|
||||||
attachmentPic: undefined,
|
|
||||||
changeReason: [],
|
|
||||||
changeContent: undefined,
|
|
||||||
costEstimation: undefined,
|
|
||||||
costEstimationFile: undefined,
|
|
||||||
fileId: undefined,
|
|
||||||
status: undefined,
|
|
||||||
remark: undefined
|
|
||||||
};
|
|
||||||
const data = reactive<PageData<DesignChangeForm, DesignChangeQuery>>({
|
|
||||||
form: { ...initFormData },
|
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@ -237,14 +137,10 @@ const data = reactive<PageData<DesignChangeForm, DesignChangeQuery>>({
|
|||||||
changeReason: undefined,
|
changeReason: undefined,
|
||||||
status: undefined,
|
status: undefined,
|
||||||
params: {}
|
params: {}
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }],
|
|
||||||
projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }]
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams } = toRefs(data);
|
||||||
|
|
||||||
/** 查询设计变更管理列表 */
|
/** 查询设计变更管理列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
@ -255,18 +151,6 @@ const getList = async () => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
|
||||||
const cancel = () => {
|
|
||||||
reset();
|
|
||||||
dialog.visible = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 表单重置 */
|
|
||||||
const reset = () => {
|
|
||||||
form.value = { ...initFormData };
|
|
||||||
designChangeFormRef.value?.resetFields();
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
@ -288,40 +172,37 @@ const handleSelectionChange = (selection: DesignChangeVO[]) => {
|
|||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
proxy.$tab.closePage(proxy.$route);
|
||||||
dialog.visible = true;
|
proxy.$router.push({
|
||||||
dialog.title = '添加设计变更';
|
path: `/design-management/designChange/indexEdit`,
|
||||||
};
|
query: {
|
||||||
|
type: 'add'
|
||||||
/** 修改按钮操作 */
|
|
||||||
const handleUpdate = async (row?: DesignChangeVO) => {
|
|
||||||
reset();
|
|
||||||
const _id = row?.id || ids.value[0];
|
|
||||||
const res = await getDesignChange(_id);
|
|
||||||
Object.assign(form.value, res.data);
|
|
||||||
form.value.changeReason = form.value.changeReason.split(',');
|
|
||||||
dialog.visible = true;
|
|
||||||
dialog.title = '修改设计变更';
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 提交按钮 */
|
|
||||||
const submitForm = () => {
|
|
||||||
designChangeFormRef.value?.validate(async (valid: boolean) => {
|
|
||||||
if (valid) {
|
|
||||||
buttonLoading.value = true;
|
|
||||||
form.value.changeReason = form.value.changeReason.join(',');
|
|
||||||
if (form.value.id) {
|
|
||||||
await updateDesignChange({ ...form.value }).finally(() => (buttonLoading.value = false));
|
|
||||||
} else {
|
|
||||||
await addDesignChange(form.value).finally(() => (buttonLoading.value = false));
|
|
||||||
}
|
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
|
||||||
dialog.visible = false;
|
|
||||||
await getList();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = async (row?: DesignChangeVO) => {
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/design-management/designChange/indexEdit`,
|
||||||
|
query: {
|
||||||
|
id: row.id,
|
||||||
|
type: 'update'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 查看按钮操作 */
|
||||||
|
const handleViewInfo = (row) => {
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/design-management/designChange/indexEdit`,
|
||||||
|
query: {
|
||||||
|
id: row.id,
|
||||||
|
type: 'view'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: DesignChangeVO) => {
|
const handleDelete = async (row?: DesignChangeVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
@ -332,13 +213,25 @@ const handleDelete = async (row?: DesignChangeVO) => {
|
|||||||
};
|
};
|
||||||
const handleView = (row) => {
|
const handleView = (row) => {
|
||||||
// 查看详情
|
// 查看详情
|
||||||
wordDetialRef.value?.openDialog(row,design_change_reason_type.value);
|
wordDetialRef.value?.openDialog(row, design_change_reason_type.value);
|
||||||
};
|
};
|
||||||
// 预览
|
// 预览
|
||||||
const onOpen = (path: string) => {
|
const onOpen = (path: string) => {
|
||||||
window.open(path, '_blank');
|
window.open(path, '_blank');
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
442
src/views/design/designChange/indexEdit.vue
Normal file
442
src/views/design/designChange/indexEdit.vue
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-4 bg-gray-50">
|
||||||
|
<div class="max-w-4xl mx-auto">
|
||||||
|
<!-- 顶部按钮区域 -->
|
||||||
|
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||||
|
<approvalButton
|
||||||
|
@submitForm="submitForm"
|
||||||
|
@approvalVerifyOpen="approvalVerifyOpen"
|
||||||
|
@handleApprovalRecord="handleApprovalRecord"
|
||||||
|
:buttonLoading="buttonLoading"
|
||||||
|
:id="form.id"
|
||||||
|
:status="form.status"
|
||||||
|
:pageType="routeParams.type"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
<!-- 表单区域 -->
|
||||||
|
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||||
|
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800">设计变更信息</h3>
|
||||||
|
</div>
|
||||||
|
<div class="p-6">
|
||||||
|
<el-form
|
||||||
|
ref="leaveFormRef"
|
||||||
|
v-loading="loading"
|
||||||
|
:disabled="routeParams.type === 'view'"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="100px"
|
||||||
|
class="space-y-4"
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-1 gap-4">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="申请单编号" prop="formNo">
|
||||||
|
<el-input v-model="form.formNo" placeholder="请输入申请单编号" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="工程名称" prop="projectName">
|
||||||
|
<el-input v-model="form.projectName" placeholder="请输入工程名称" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="提出单位" prop="submitUnit">
|
||||||
|
<el-input v-model="form.submitUnit" placeholder="请输入提出单位" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="专业" prop="specialty">
|
||||||
|
<el-input v-model="form.specialty" placeholder="请输入专业" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="提出日期" prop="submitDate">
|
||||||
|
<el-date-picker clearable v-model="form.submitDate" type="date" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择提出日期">
|
||||||
|
</el-date-picker> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="卷册名称" prop="volumeName"> <el-input v-model="form.volumeName" placeholder="请输入卷册名称" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="卷册号" prop="volumeNo"> <el-input v-model="form.volumeNo" placeholder="请输入卷册号" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="附图" prop="attachmentPic"> <image-upload v-model="form.attachmentPic" :fileSize="100" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="变更原因" prop="changeReason">
|
||||||
|
<el-checkbox-group v-model="form.changeReason">
|
||||||
|
<el-checkbox v-for="dict in design_change_reason_type" :key="dict.value" :value="dict.value">
|
||||||
|
{{ dict.label }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item></el-col
|
||||||
|
>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="变更内容" prop="changeContent">
|
||||||
|
<el-input v-model="form.changeContent" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="变更费用估算表" label-width="110px" prop="costEstimationFile">
|
||||||
|
<file-upload v-model="form.costEstimationFile" :fileSize="100" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="变更文件" prop="fileId"> <file-upload v-model="form.fileId" :fileSize="100" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
<el-col :span="24"
|
||||||
|
><el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||||
|
></el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<!-- 提交组件 -->
|
||||||
|
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||||
|
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||||
|
<!-- 流程选择对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
draggable
|
||||||
|
v-model="dialogVisible.visible"
|
||||||
|
:title="dialogVisible.title"
|
||||||
|
:before-close="handleClose"
|
||||||
|
width="500"
|
||||||
|
class="rounded-lg shadow-lg"
|
||||||
|
>
|
||||||
|
<div class="p-4">
|
||||||
|
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||||
|
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||||
|
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||||
|
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||||
|
>取消</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||||
|
>确认</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Leave" lang="ts">
|
||||||
|
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||||
|
import { startWorkFlow } from '@/api/workflow/task';
|
||||||
|
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||||
|
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||||
|
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||||
|
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { getDesignChange, addDesignChange, updateDesignChange } from '@/api/design/designChange';
|
||||||
|
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||||
|
|
||||||
|
// 获取用户 store
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const loading = ref(true);
|
||||||
|
//路由参数
|
||||||
|
const routeParams = ref<Record<string, any>>({});
|
||||||
|
const flowCodeOptions = [
|
||||||
|
{
|
||||||
|
value: currentProject.value?.id + '_designchanged',
|
||||||
|
label: '设计变更审批'
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const flowCode = ref<string>('');
|
||||||
|
const status = ref<string>('');
|
||||||
|
const dialogVisible = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: '流程定义'
|
||||||
|
});
|
||||||
|
//提交组件
|
||||||
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||||
|
//审批记录组件
|
||||||
|
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||||
|
//按钮组件
|
||||||
|
const approvalButtonRef = ref<InstanceType<typeof ApprovalButton>>();
|
||||||
|
|
||||||
|
const leaveFormRef = ref<ElFormInstance>();
|
||||||
|
const dialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: '',
|
||||||
|
isEdit: false
|
||||||
|
});
|
||||||
|
const submitFormData = ref<StartProcessBo>({
|
||||||
|
businessId: '',
|
||||||
|
flowCode: '',
|
||||||
|
variables: {}
|
||||||
|
});
|
||||||
|
const taskVariables = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
const initFormData = {
|
||||||
|
id: undefined,
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
formNo: undefined,
|
||||||
|
projectName: undefined,
|
||||||
|
submitUnit: undefined,
|
||||||
|
specialty: undefined,
|
||||||
|
submitDate: undefined,
|
||||||
|
volumeName: undefined,
|
||||||
|
volumeNo: undefined,
|
||||||
|
attachmentPic: undefined,
|
||||||
|
changeReason: [],
|
||||||
|
changeContent: undefined,
|
||||||
|
costEstimation: undefined,
|
||||||
|
costEstimationFile: undefined,
|
||||||
|
fileId: undefined,
|
||||||
|
status: undefined,
|
||||||
|
remark: undefined
|
||||||
|
};
|
||||||
|
const data = reactive({
|
||||||
|
form: { ...initFormData },
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
fileName: undefined,
|
||||||
|
fileType: undefined,
|
||||||
|
fileSuffix: undefined,
|
||||||
|
fileStatus: undefined,
|
||||||
|
originalName: undefined,
|
||||||
|
newest: undefined,
|
||||||
|
params: {}
|
||||||
|
},
|
||||||
|
rules: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.visible = false;
|
||||||
|
flowCode.value = '';
|
||||||
|
buttonLoading.value = false;
|
||||||
|
};
|
||||||
|
const { form, rules } = toRefs(data);
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = { ...initFormData };
|
||||||
|
leaveFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取详情 */
|
||||||
|
const getInfo = () => {
|
||||||
|
loading.value = true;
|
||||||
|
buttonLoading.value = false;
|
||||||
|
nextTick(async () => {
|
||||||
|
const res = await getDesignChange(routeParams.value.id);
|
||||||
|
Object.assign(form.value, res.data);
|
||||||
|
if(form.value.changeReason.length >0){
|
||||||
|
form.value.changeReason = form.value.changeReason.split(',');
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
buttonLoading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = (status1: string) => {
|
||||||
|
status.value = status1;
|
||||||
|
var changeReason=''
|
||||||
|
if(form.value.changeReason.length >0){
|
||||||
|
changeReason = form.value.changeReason.join(',');
|
||||||
|
}
|
||||||
|
leaveFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true;
|
||||||
|
var res;
|
||||||
|
if (form.value.id) {
|
||||||
|
res = await updateDesignChange({...form.value,changeReason}).finally(() => (buttonLoading.value = false));
|
||||||
|
} else {
|
||||||
|
res = await addDesignChange({...form.value,changeReason}).finally(() => (buttonLoading.value = false));
|
||||||
|
}
|
||||||
|
if (res.code == 200) {
|
||||||
|
dialog.visible = false;
|
||||||
|
submit(status.value, res.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitFlow = async () => {
|
||||||
|
handleStartWorkFlow(form.value);
|
||||||
|
dialogVisible.visible = false;
|
||||||
|
};
|
||||||
|
//提交申请
|
||||||
|
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||||
|
try {
|
||||||
|
submitFormData.value.flowCode = flowCode.value;
|
||||||
|
submitFormData.value.businessId = data.id;
|
||||||
|
//流程变量
|
||||||
|
taskVariables.value = {
|
||||||
|
// leave4/5 使用的流程变量
|
||||||
|
userList: ['1', '3', '4']
|
||||||
|
};
|
||||||
|
submitFormData.value.variables = taskVariables.value;
|
||||||
|
const resp = await startWorkFlow(submitFormData.value);
|
||||||
|
if (submitVerifyRef.value) {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//审批记录
|
||||||
|
const handleApprovalRecord = () => {
|
||||||
|
approvalRecordRef.value.init(form.value.id);
|
||||||
|
};
|
||||||
|
//提交回调
|
||||||
|
const submitCallback = async () => {
|
||||||
|
await proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.go(-1);
|
||||||
|
};
|
||||||
|
//审批
|
||||||
|
const approvalVerifyOpen = async () => {
|
||||||
|
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||||
|
};
|
||||||
|
// 图纸上传成功之后 开始提交
|
||||||
|
const submit = async (status, data) => {
|
||||||
|
form.value = data;
|
||||||
|
if (status === 'draft') {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
proxy?.$modal.msgSuccess('暂存成功');
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.go(-1);
|
||||||
|
} else {
|
||||||
|
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||||
|
flowCode.value = flowCodeOptions[0].value;
|
||||||
|
dialogVisible.visible = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//说明启动过先随意穿个参数
|
||||||
|
if (flowCode.value === '' || flowCode.value === null) {
|
||||||
|
flowCode.value = 'xx';
|
||||||
|
}
|
||||||
|
await handleStartWorkFlow(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(async () => {
|
||||||
|
routeParams.value = proxy.$route.query;
|
||||||
|
reset();
|
||||||
|
loading.value = false;
|
||||||
|
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||||
|
getInfo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
/* 全局样式 */
|
||||||
|
:root {
|
||||||
|
--primary: #409eff;
|
||||||
|
--primary-light: #66b1ff;
|
||||||
|
--primary-dark: #3a8ee6;
|
||||||
|
--success: #67c23a;
|
||||||
|
--warning: #e6a23c;
|
||||||
|
--danger: #f56c6c;
|
||||||
|
--info: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单样式优化 */
|
||||||
|
.el-form-item {
|
||||||
|
.el-form-item__label {
|
||||||
|
color: #606266;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__inner,
|
||||||
|
.el-select .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s,
|
||||||
|
box-shadow 0.2s;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s,
|
||||||
|
box-shadow 0.2s;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮样式优化 */
|
||||||
|
.el-button {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&.is-primary {
|
||||||
|
background-color: var(--primary);
|
||||||
|
border-color: var(--primary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--primary-light);
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--primary-dark);
|
||||||
|
border-color: var(--primary-dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-text {
|
||||||
|
color: var(--primary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--primary-light);
|
||||||
|
background-color: rgba(64, 158, 255, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片样式优化 */
|
||||||
|
.el-card {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
/* transform: translateY(-2px); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 对话框样式优化 */
|
||||||
|
.el-dialog {
|
||||||
|
.el-dialog__header {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
padding: 15px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__footer {
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -88,8 +88,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Drawing" lang="ts">
|
<script setup name="Drawing" lang="ts">
|
||||||
import { listDrawing, getDrawing, delDrawing, addDrawing, updateDrawing } from '@/api/design/drawing';
|
import { listDrawing, delDrawing } from '@/api/design/drawing';
|
||||||
import { DrawingVO, DrawingQuery, DrawingForm } from '@/api/design/drawing/types';
|
import { DrawingVO } from '@/api/design/drawing/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { LeaveVO } from '@/api/workflow/leave/types';
|
import { LeaveVO } from '@/api/workflow/leave/types';
|
||||||
import { cancelProcessApply } from '@/api/workflow/instance';
|
import { cancelProcessApply } from '@/api/workflow/instance';
|
||||||
@ -110,65 +110,24 @@ const ids = ref<Array<string | number>>([]);
|
|||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const fileList = ref([]); // 存储上传的文件列表
|
|
||||||
const selectedFile = ref(null); // 当前选中的文件
|
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const drawingFormRef = ref<ElFormInstance>();
|
|
||||||
const activeName = ref('1');
|
const activeName = ref('1');
|
||||||
const dialog = reactive({
|
const data = reactive({
|
||||||
visible: false,
|
|
||||||
title: '',
|
|
||||||
isEdit: false
|
|
||||||
});
|
|
||||||
const initFormData: DrawingForm = {
|
|
||||||
id: undefined,
|
|
||||||
projectId: currentProject.value?.id,
|
|
||||||
versionNumber: undefined,
|
|
||||||
fileName: undefined,
|
|
||||||
fileUrl: undefined,
|
|
||||||
fileType: undefined,
|
|
||||||
fileSuffix: undefined,
|
|
||||||
originalName: undefined,
|
|
||||||
remark: undefined
|
|
||||||
};
|
|
||||||
const data = reactive<PageData<DrawingForm, DrawingQuery>>({
|
|
||||||
form: { ...initFormData },
|
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
fileName: undefined,
|
fileName: undefined,
|
||||||
fileType: undefined,
|
fileType: 1,
|
||||||
fileSuffix: undefined,
|
fileSuffix: undefined,
|
||||||
fileStatus: undefined,
|
fileStatus: undefined,
|
||||||
originalName: undefined,
|
originalName: undefined,
|
||||||
newest: undefined,
|
newest: undefined,
|
||||||
params: {}
|
params: {}
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
versionNumber: [{ required: true, message: '版本号不能为空', trigger: 'blur' }],
|
|
||||||
fileName: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
|
|
||||||
fileType: [{ required: true, message: '文件类型不能为空', trigger: 'change' }],
|
|
||||||
file: [
|
|
||||||
{
|
|
||||||
validator: (rule, value, callback) => {
|
|
||||||
console.log(dialog.isEdit);
|
|
||||||
console.log(fileList.value);
|
|
||||||
|
|
||||||
// 新增时必须上传文件
|
|
||||||
if (!dialog.isEdit && !fileList.value.length) {
|
|
||||||
callback(new Error('请上传图纸文件'));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
trigger: 'change'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams } = toRefs(data);
|
||||||
|
|
||||||
/** 查询图纸管理列表 */
|
/** 查询图纸管理列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
@ -179,20 +138,6 @@ const getList = async () => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
|
||||||
const cancel = () => {
|
|
||||||
reset();
|
|
||||||
dialog.visible = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 表单重置 */
|
|
||||||
const reset = () => {
|
|
||||||
form.value = { ...initFormData };
|
|
||||||
drawingFormRef.value?.resetFields();
|
|
||||||
fileList.value = [];
|
|
||||||
selectedFile.value = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
@ -216,7 +161,7 @@ const handleSelectionChange = (selection: DrawingVO[]) => {
|
|||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/drawing/indexEdit`,
|
path: `/design-management/drawing/indexEdit`,
|
||||||
query: {
|
query: {
|
||||||
type: 'add'
|
type: 'add'
|
||||||
}
|
}
|
||||||
@ -227,7 +172,7 @@ const handleAdd = () => {
|
|||||||
const handleUpdate = async (row?: DrawingVO) => {
|
const handleUpdate = async (row?: DrawingVO) => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/drawing/indexEdit`,
|
path: `/design-management/drawing/indexEdit`,
|
||||||
query: {
|
query: {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
type: 'update'
|
type: 'update'
|
||||||
@ -253,7 +198,7 @@ const handleView = (row) => {
|
|||||||
const handleViewInfo = (row?: LeaveVO) => {
|
const handleViewInfo = (row?: LeaveVO) => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/drawing/indexEdit`,
|
path: `/design-management/drawing/indexEdit`,
|
||||||
query: {
|
query: {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
type: 'view'
|
type: 'view'
|
||||||
@ -283,4 +228,16 @@ const handleClick = (val) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -176,7 +176,7 @@ const data = reactive<PageData<LeaveForm, LeaveQuery>>({
|
|||||||
versionNumber: [{ required: true, message: '版本号不能为空', trigger: 'blur' }],
|
versionNumber: [{ required: true, message: '版本号不能为空', trigger: 'blur' }],
|
||||||
fileName: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
|
fileName: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
|
||||||
fileType: [{ required: true, message: '文件类型不能为空', trigger: 'change' }],
|
fileType: [{ required: true, message: '文件类型不能为空', trigger: 'change' }],
|
||||||
file: [
|
fileUrl: [
|
||||||
{
|
{
|
||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
// 新增时必须上传文件
|
// 新增时必须上传文件
|
||||||
|
|||||||
@ -14,8 +14,8 @@
|
|||||||
<el-input v-model="queryParams.originalName" placeholder="请输入原文件名" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.originalName" placeholder="请输入原文件名" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="审核状态" prop="status">
|
<el-form-item label="审核状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" placeholder="请选择审核状态" clearable >
|
<el-select v-model="queryParams.status" placeholder="请选择审核状态" clearable>
|
||||||
<el-option v-for="dict in wf_business_status" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
<el-option v-for="dict in wf_business_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
@ -46,12 +46,11 @@
|
|||||||
<el-table-column label="原文件名" align="center" prop="originalName" />
|
<el-table-column label="原文件名" align="center" prop="originalName" />
|
||||||
<el-table-column label="流程状态" align="center" prop="status">
|
<el-table-column label="流程状态" align="center" prop="status">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<dict-tag :options="wf_business_status" :value="scope.row.status"/>
|
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="备注" align="center" prop="remark" />
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
<el-table-column label="上传时间" align="center" prop="createTime" width="180">
|
<el-table-column label="上传时间" align="center" prop="createTime" width="180"> </el-table-column>
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding">
|
<el-table-column label="操作" align="center" class-name="small-padding">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
@ -68,7 +67,9 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" size="small" icon="View" v-if="scope.row.status != 'draft'" @click="handleViewInfo(scope.row)">查看</el-button>
|
<el-button type="primary" size="small" icon="View" v-if="scope.row.status != 'draft'" @click="handleViewInfo(scope.row)"
|
||||||
|
>查看</el-button
|
||||||
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5" v-if="scope.row.status === 'waiting'">
|
<el-col :span="1.5" v-if="scope.row.status === 'waiting'">
|
||||||
<el-button size="small" type="primary" icon="Notification" @click="handleCancelProcessApply(scope.row.id)">撤销</el-button>
|
<el-button size="small" type="primary" icon="Notification" @click="handleCancelProcessApply(scope.row.id)">撤销</el-button>
|
||||||
@ -77,15 +78,14 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="SpecialScheme" lang="ts">
|
<script setup name="SpecialScheme" lang="ts">
|
||||||
import { listSpecialScheme, getSpecialScheme, delSpecialScheme, addSpecialScheme, updateSpecialScheme } from '@/api/design/specialScheme';
|
import { listSpecialScheme, delSpecialScheme } from '@/api/design/specialScheme';
|
||||||
import { SpecialSchemeVO, SpecialSchemeQuery, SpecialSchemeForm } from '@/api/design/specialScheme/types';
|
import { SpecialSchemeVO } from '@/api/design/specialScheme/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { cancelProcessApply } from '@/api/workflow/instance';
|
import { cancelProcessApply } from '@/api/workflow/instance';
|
||||||
|
|
||||||
@ -96,7 +96,6 @@ const userStore = useUserStoreHook();
|
|||||||
// 从 store 中获取项目列表和当前选中的项目
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
const specialSchemeList = ref<SpecialSchemeVO[]>([]);
|
const specialSchemeList = ref<SpecialSchemeVO[]>([]);
|
||||||
const buttonLoading = ref(false);
|
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
const ids = ref<Array<string | number>>([]);
|
const ids = ref<Array<string | number>>([]);
|
||||||
@ -105,24 +104,8 @@ const multiple = ref(true);
|
|||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
|
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const specialSchemeFormRef = ref<ElFormInstance>();
|
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const data = reactive({
|
||||||
visible: false,
|
|
||||||
title: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const initFormData: SpecialSchemeForm = {
|
|
||||||
id: undefined,
|
|
||||||
projectId: currentProject.value?.id,
|
|
||||||
versionNumber: undefined,
|
|
||||||
fileName: undefined,
|
|
||||||
fileUrl: undefined,
|
|
||||||
fileSuffix: undefined,
|
|
||||||
remark: undefined,
|
|
||||||
}
|
|
||||||
const data = reactive<PageData<SpecialSchemeForm, SpecialSchemeQuery>>({
|
|
||||||
form: {...initFormData},
|
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@ -131,20 +114,11 @@ const data = reactive<PageData<SpecialSchemeForm, SpecialSchemeQuery>>({
|
|||||||
fileName: undefined,
|
fileName: undefined,
|
||||||
originalName: undefined,
|
originalName: undefined,
|
||||||
status: undefined,
|
status: undefined,
|
||||||
params: {
|
params: {}
|
||||||
}
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
versionNumber: [
|
|
||||||
{ required: true, message: "版本号不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
fileName: [
|
|
||||||
{ required: true, message: "文件名称不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams } = toRefs(data);
|
||||||
|
|
||||||
/** 查询专项方案管理列表 */
|
/** 查询专项方案管理列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
@ -153,96 +127,66 @@ const getList = async () => {
|
|||||||
specialSchemeList.value = res.rows;
|
specialSchemeList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
|
||||||
const cancel = () => {
|
|
||||||
reset();
|
|
||||||
dialog.visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 表单重置 */
|
|
||||||
const reset = () => {
|
|
||||||
form.value = {...initFormData};
|
|
||||||
specialSchemeFormRef.value?.resetFields();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: SpecialSchemeVO[]) => {
|
const handleSelectionChange = (selection: SpecialSchemeVO[]) => {
|
||||||
ids.value = selection.map(item => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/specialScheme/indexEdit`,
|
path: `/design-management/specialScheme/indexEdit`,
|
||||||
query: {
|
query: {
|
||||||
type: 'add'
|
type: 'add'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: SpecialSchemeVO) => {
|
const handleUpdate = async (row?: SpecialSchemeVO) => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/specialScheme/indexEdit`,
|
path: `/design-management/specialScheme/indexEdit`,
|
||||||
query: {
|
query: {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
type: 'update'
|
type: 'update'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
|
||||||
const submitForm = () => {
|
|
||||||
specialSchemeFormRef.value?.validate(async (valid: boolean) => {
|
|
||||||
if (valid) {
|
|
||||||
buttonLoading.value = true;
|
|
||||||
if (form.value.id) {
|
|
||||||
await updateSpecialScheme(form.value).finally(() => buttonLoading.value = false);
|
|
||||||
} else {
|
|
||||||
await addSpecialScheme(form.value).finally(() => buttonLoading.value = false);
|
|
||||||
}
|
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
|
||||||
dialog.visible = false;
|
|
||||||
await getList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: SpecialSchemeVO) => {
|
const handleDelete = async (row?: SpecialSchemeVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除专项方案管理编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
|
await proxy?.$modal.confirm('是否确认删除专项方案管理编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||||
await delSpecialScheme(_ids);
|
await delSpecialScheme(_ids);
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
await getList();
|
await getList();
|
||||||
}
|
};
|
||||||
const handleView = (row) => {
|
const handleView = (row) => {
|
||||||
var url= row.file.url
|
var url = row.file.url;
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
};
|
};
|
||||||
/** 查看按钮操作 */
|
/** 查看按钮操作 */
|
||||||
const handleViewInfo = (row) => {
|
const handleViewInfo = (row) => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/specialScheme/indexEdit`,
|
path: `/design-management/specialScheme/indexEdit`,
|
||||||
query: {
|
query: {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
type: 'view'
|
type: 'view'
|
||||||
@ -264,4 +208,16 @@ const handleCancelProcessApply = async (id: string) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,143 +1,155 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-tabs v-model="activeName" class="demo-tabs p5" @tab-click="handleCheckMian">
|
<div>
|
||||||
<el-tab-pane label="资料" name="first">
|
<el-tabs v-model="activeName" class="demo-tabs p5" @tab-click="handleCheckMian">
|
||||||
<div class="profile_engin">
|
<el-tab-pane label="资料" name="first">
|
||||||
<div class="box_info">
|
<div class="profile_engin">
|
||||||
<div class="tree_left1" id="tree_left1">
|
<div class="box_info">
|
||||||
<div class="file_upload check_select">
|
<div class="tree_left1" id="tree_left1">
|
||||||
<div class="box_btn">
|
<div class="file_upload check_select">
|
||||||
<file-upload
|
<div class="box_btn">
|
||||||
v-model="state.paramsQuery.file"
|
<file-upload
|
||||||
:limit="100"
|
v-model="state.paramsQuery.file"
|
||||||
:uploadUrl="uploadUrl"
|
:limit="100"
|
||||||
:params="uploadParams"
|
:uploadUrl="uploadUrl"
|
||||||
:on-upload-success="uploadFile"
|
:params="uploadParams"
|
||||||
:fileType="[]"
|
:on-upload-success="uploadFile"
|
||||||
|
:fileType="[]"
|
||||||
|
>
|
||||||
|
<el-button type="primary" style="float: left" :disabled="!state.parentPid">
|
||||||
|
<el-icon size="small"><Plus /></el-icon>上传文件
|
||||||
|
</el-button>
|
||||||
|
</file-upload>
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" :disabled="!state.parentPid" @click="onExport"
|
||||||
|
><el-icon><Download /></el-icon>下载</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" @click="onBook"
|
||||||
|
><el-icon><View /></el-icon>查看全项目文件</el-button
|
||||||
>
|
>
|
||||||
<el-button type="primary" style="float: left" :disabled="!state.parentPid">
|
|
||||||
<el-icon size="small"><Plus /></el-icon>上传文件
|
|
||||||
</el-button>
|
|
||||||
</file-upload>
|
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" :disabled="!state.parentPid" @click="onExport"
|
<div class="file_upload check_select">
|
||||||
><el-icon><Download /></el-icon>下载</el-button
|
<el-input class="input_left" v-model="filterText" size="small" placeholder="请输入文件名称" />
|
||||||
|
</div>
|
||||||
|
<el-tree
|
||||||
|
ref="treeRef"
|
||||||
|
highlight-current
|
||||||
|
:default-expand-all="state.checked"
|
||||||
|
:filter-node-method="filterFolder"
|
||||||
|
:data="state.treeList"
|
||||||
|
node-key="id"
|
||||||
|
accordion
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
:current-node-key="state.selectedNodeId"
|
||||||
>
|
>
|
||||||
<el-button type="primary" @click="onBook"
|
<template #default="{ node, data }">
|
||||||
><el-icon><View /></el-icon>查看全项目文件</el-button
|
<span class="custom-tree-node">
|
||||||
>
|
<el-icon color="#f1a81a"><FolderOpened /></el-icon>
|
||||||
</div>
|
<span>{{ node.label }}</span>
|
||||||
<div class="file_upload check_select">
|
</span>
|
||||||
<el-input class="input_left" v-model="filterText" size="small" placeholder="请输入文件名称" />
|
|
||||||
</div>
|
|
||||||
<el-tree
|
|
||||||
ref="treeRef"
|
|
||||||
highlight-current
|
|
||||||
:default-expand-all="state.checked"
|
|
||||||
:filter-node-method="filterFolder"
|
|
||||||
:data="state.treeList"
|
|
||||||
node-key="id"
|
|
||||||
accordion
|
|
||||||
:expand-on-click-node="false"
|
|
||||||
@node-click="handleNodeClick"
|
|
||||||
:current-node-key="state.selectedNodeId"
|
|
||||||
>
|
|
||||||
<template #default="{ node, data }">
|
|
||||||
<span class="custom-tree-node">
|
|
||||||
<el-icon color="#f1a81a"><FolderOpened /></el-icon>
|
|
||||||
<span>{{ node.label }}</span>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-tree>
|
|
||||||
<div class="resize-handle resize-handle-right right"></div>
|
|
||||||
</div>
|
|
||||||
<div class="list_right" id="list_right1">
|
|
||||||
<div>
|
|
||||||
<el-form :model="state.paramsQuery" ref="queryRef" :inline="true" label-width="100px">
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="7" class="colBlock">
|
|
||||||
<el-form-item label="文件名称" prop="fileName">
|
|
||||||
<el-input
|
|
||||||
v-model="state.paramsQuery.fileName"
|
|
||||||
placeholder="请输入文件名称"
|
|
||||||
clearable
|
|
||||||
@keyup.enter.native="getdocumentDataList"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="6" class="m-l10">
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="searchInfo"
|
|
||||||
><el-icon><Search /></el-icon>搜索</el-button
|
|
||||||
>
|
|
||||||
<el-button @click="resetQuery"
|
|
||||||
><el-icon><Refresh /></el-icon>重置</el-button
|
|
||||||
>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
<el-table v-loading="state.loading" :data="state.infoList" height="67vh" border>
|
|
||||||
<el-table-column label="序号" align="center" type="index" min-width="50px" />
|
|
||||||
<el-table-column label="文件名称" align="center" prop="fileName"></el-table-column>
|
|
||||||
<el-table-column label="文件类型" align="center" prop="fileSuffix" width="100px" />
|
|
||||||
|
|
||||||
<el-table-column label="上传时间" align="center" prop="createTime"> </el-table-column>
|
|
||||||
<el-table-column label="操作" align="center" width="300">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button type="primary" link @click="handleView(scope.row)" v-if="acceptType.includes(scope.row.fileSuffix)"
|
|
||||||
><el-icon><View /></el-icon>查看</el-button
|
|
||||||
>
|
|
||||||
<el-button type="primary" v-if="state.wordType.includes(scope.row.fileSuffix)" link @click="updataView(scope.row)"
|
|
||||||
><el-icon><EditPen /></el-icon>修改文件</el-button
|
|
||||||
>
|
|
||||||
<el-button type="primary" link @click="onExportView(scope.row)"
|
|
||||||
><el-icon><Download /></el-icon>下载</el-button
|
|
||||||
>
|
|
||||||
<el-button type="success" link @click="updateName(scope.row)"
|
|
||||||
><el-icon><EditPen /></el-icon>修改名称</el-button
|
|
||||||
>
|
|
||||||
<el-button type="danger" link @click="handleDelete(scope.row)"
|
|
||||||
><el-icon><DeleteFilled /></el-icon>删除</el-button
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-tree>
|
||||||
</el-table>
|
<div class="resize-handle resize-handle-right right"></div>
|
||||||
<pagination
|
</div>
|
||||||
:total="state.total"
|
<div class="list_right" id="list_right1">
|
||||||
v-model:page="state.paramsQuery.pageNum"
|
<div>
|
||||||
v-model:limit="state.paramsQuery.pageSize"
|
<el-form :model="state.paramsQuery" ref="queryRef" :inline="true" label-width="100px">
|
||||||
@pagination="getdocumentDataList"
|
<el-row>
|
||||||
/>
|
<el-col :span="7" class="colBlock">
|
||||||
|
<el-form-item label="文件名称" prop="fileName">
|
||||||
|
<el-input
|
||||||
|
v-model="state.paramsQuery.fileName"
|
||||||
|
placeholder="请输入文件名称"
|
||||||
|
clearable
|
||||||
|
@keyup.enter.native="getdocumentDataList"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" class="m-l10">
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="searchInfo"
|
||||||
|
><el-icon><Search /></el-icon>搜索</el-button
|
||||||
|
>
|
||||||
|
<el-button @click="resetQuery"
|
||||||
|
><el-icon><Refresh /></el-icon>重置</el-button
|
||||||
|
>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<el-table v-loading="state.loading" :data="state.infoList" height="67vh" border>
|
||||||
|
<el-table-column label="序号" align="center" type="index" min-width="50px" />
|
||||||
|
<el-table-column label="文件名称" align="center" prop="fileName"></el-table-column>
|
||||||
|
<el-table-column label="文件类型" align="center" prop="fileSuffix" width="100px" />
|
||||||
|
<el-table-column label="流程状态" align="center" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="上传时间" align="center" prop="createTime"> </el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" width="300">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="primary" link @click="handleApproval(scope.row)"
|
||||||
|
><el-icon><Plus /></el-icon>审批</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" link @click="handleViewApproval(scope.row)"
|
||||||
|
><el-icon><View /></el-icon>流程查看</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" link @click="handleView(scope.row)" v-if="acceptType.includes(scope.row.fileSuffix)"
|
||||||
|
><el-icon><View /></el-icon>查看</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" v-if="state.wordType.includes(scope.row.fileSuffix)" link @click="updataView(scope.row)"
|
||||||
|
><el-icon><EditPen /></el-icon>修改文件</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" link @click="onExportView(scope.row)"
|
||||||
|
><el-icon><Download /></el-icon>下载</el-button
|
||||||
|
>
|
||||||
|
<el-button type="success" link @click="updateName(scope.row)"
|
||||||
|
><el-icon><EditPen /></el-icon>修改名称</el-button
|
||||||
|
>
|
||||||
|
<el-button type="danger" link @click="handleDelete(scope.row)"
|
||||||
|
><el-icon><DeleteFilled /></el-icon>删除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination
|
||||||
|
:total="state.total"
|
||||||
|
v-model:page="state.paramsQuery.pageNum"
|
||||||
|
v-model:limit="state.paramsQuery.pageSize"
|
||||||
|
@pagination="getdocumentDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<documentsDeailsVue ref="documentDetailRef" v-if="state.showDocumentDetail" @onClose="onClose"></documentsDeailsVue>
|
||||||
|
<documentsEdit ref="documentDataEditRef" v-if="state.showdocumentDataEdit" @onClose="onCloseEdit"></documentsEdit>
|
||||||
|
<bookFile ref="bookFileRef" @onExportView="onExportView" @onBook="handleView" @onExport="onExport"></bookFile>
|
||||||
|
<el-dialog draggable title="上传文件" v-model="uploadFileder" width="30%">
|
||||||
|
<file-upload v-model="state.paramsQuery.file"></file-upload>
|
||||||
|
<template #footer>
|
||||||
|
<span>
|
||||||
|
<el-button @click="uploadFileder = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="subMitUpload">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
<documentsDeailsVue ref="documentDetailRef" v-if="state.showDocumentDetail" @onClose="onClose"></documentsDeailsVue>
|
<el-image-viewer
|
||||||
<documentsEdit ref="documentDataEditRef" v-if="state.showdocumentDataEdit" @onClose="onCloseEdit"></documentsEdit>
|
ref="imageRef"
|
||||||
<bookFile ref="bookFileRef" @onExportView="onExportView" @onBook="handleView" @onExport="onExport"></bookFile>
|
style="width: 100%; height: 100%"
|
||||||
<el-dialog draggable title="上传文件" v-model="uploadFileder" width="30%">
|
:url-list="[imgUrl]"
|
||||||
<file-upload v-model="state.paramsQuery.file"></file-upload>
|
v-if="imgUrl"
|
||||||
<template #footer>
|
show-progress
|
||||||
<span>
|
fit="cover"
|
||||||
<el-button @click="uploadFileder = false">取消</el-button>
|
@close="imgUrl = ''"
|
||||||
<el-button type="primary" @click="subMitUpload">确定</el-button>
|
/>
|
||||||
</span>
|
</el-tab-pane>
|
||||||
</template>
|
<el-tab-pane label="回收站" name="second">
|
||||||
</el-dialog>
|
<RecyclingStation ref="recylingRef"></RecyclingStation>
|
||||||
</div>
|
</el-tab-pane>
|
||||||
<el-image-viewer
|
</el-tabs>
|
||||||
ref="imageRef"
|
</div>
|
||||||
style="width: 100%; height: 100%"
|
|
||||||
:url-list="[imgUrl]"
|
|
||||||
v-if="imgUrl"
|
|
||||||
show-progress
|
|
||||||
fit="cover"
|
|
||||||
@close="imgUrl = ''"
|
|
||||||
/>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="回收站" name="second">
|
|
||||||
<RecyclingStation ref="recylingRef"></RecyclingStation>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="KnowledgeDocument" lang="ts">
|
<script setup name="KnowledgeDocument" lang="ts">
|
||||||
@ -153,7 +165,6 @@ import {
|
|||||||
import documentsEdit from './component/documentsEdit.vue';
|
import documentsEdit from './component/documentsEdit.vue';
|
||||||
import documentsDeailsVue from './component/documentsDeails.vue';
|
import documentsDeailsVue from './component/documentsDeails.vue';
|
||||||
import RecyclingStation from './component/recyclingStation.vue';
|
import RecyclingStation from './component/recyclingStation.vue';
|
||||||
|
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import bookFile from './component/bookFile.vue';
|
import bookFile from './component/bookFile.vue';
|
||||||
const activeName = ref('first');
|
const activeName = ref('first');
|
||||||
@ -162,6 +173,7 @@ const { proxy } = getCurrentInstance() as any;
|
|||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
// 从 store 中获取项目列表和当前选中的项目
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||||
const uploadUrl = computed(() => {
|
const uploadUrl = computed(() => {
|
||||||
return `/design/technicalStandard/file`;
|
return `/design/technicalStandard/file`;
|
||||||
});
|
});
|
||||||
@ -171,7 +183,6 @@ const uploadParams = computed(() => {
|
|||||||
projectId: state.projectId
|
projectId: state.projectId
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const imgUrl = ref<string>('');
|
const imgUrl = ref<string>('');
|
||||||
const filterText = ref('');
|
const filterText = ref('');
|
||||||
const treeRef = ref();
|
const treeRef = ref();
|
||||||
@ -289,7 +300,7 @@ const setInfo = (arr) => {
|
|||||||
const handleNodeClick = (row) => {
|
const handleNodeClick = (row) => {
|
||||||
state.parentRow = row;
|
state.parentRow = row;
|
||||||
state.parentPid = row.parentId;
|
state.parentPid = row.parentId;
|
||||||
console.log('🚀 ~ handleNodeClick ~ state.parentPid:', state.parentPid);
|
console.log(row);
|
||||||
state.parentName = row.label;
|
state.parentName = row.label;
|
||||||
state.paramsQuery.folderId = row.id;
|
state.paramsQuery.folderId = row.id;
|
||||||
getdocumentDataList();
|
getdocumentDataList();
|
||||||
@ -443,6 +454,44 @@ const onBook = () => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
gettreeStructureData();
|
gettreeStructureData();
|
||||||
});
|
});
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
state.projectId = nid;
|
||||||
|
state.paramsQuery.projectId = nid;
|
||||||
|
if (activeName.value === 'first') {
|
||||||
|
gettreeStructureData();
|
||||||
|
} else {
|
||||||
|
// 回收站
|
||||||
|
recylingRef.value.getDocumentDataList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
|
const handleApproval = (row) => {
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/design-management/technicalStandard/indexEdit`,
|
||||||
|
query: {
|
||||||
|
id: row.id,
|
||||||
|
type: 'update'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleViewApproval = (row) => {
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/design-management/technicalStandard/indexEdit`,
|
||||||
|
query: {
|
||||||
|
id: row.id,
|
||||||
|
type: 'view'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -473,7 +522,7 @@ onMounted(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.tree_left1 {
|
.tree_left1 {
|
||||||
width: 30%;
|
width: 20%;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid #dddddd;
|
border: 1px solid #dddddd;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
@ -536,7 +585,7 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.list_right {
|
.list_right {
|
||||||
width: 69.5%;
|
width: 79.5%;
|
||||||
background: white;
|
background: white;
|
||||||
border: 1px solid #ededed;
|
border: 1px solid #ededed;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|||||||
356
src/views/design/technicalStandard/indexEdit.vue
Normal file
356
src/views/design/technicalStandard/indexEdit.vue
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-4 bg-gray-50">
|
||||||
|
<div class="max-w-4xl mx-auto">
|
||||||
|
<!-- 顶部按钮区域 -->
|
||||||
|
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||||
|
<approvalButton
|
||||||
|
@submitForm="submitForm"
|
||||||
|
@approvalVerifyOpen="approvalVerifyOpen"
|
||||||
|
@handleApprovalRecord="handleApprovalRecord"
|
||||||
|
:buttonLoading="buttonLoading"
|
||||||
|
:id="form.id"
|
||||||
|
:status="form.status"
|
||||||
|
:pageType="routeParams.type"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
<!-- 表单区域 -->
|
||||||
|
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||||
|
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800">设计原则</h3>
|
||||||
|
</div>
|
||||||
|
<div class="p-6">
|
||||||
|
<el-form
|
||||||
|
ref="leaveFormRef"
|
||||||
|
v-loading="loading"
|
||||||
|
:disabled="routeParams.type === 'view'"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="100px"
|
||||||
|
class="space-y-4"
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-1 gap-4">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="文件名称" prop="formNo">
|
||||||
|
<el-input disabled v-model="form.fileName" placeholder="请输入文件名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="文件" prop="formNo">
|
||||||
|
<div style="display: flex;">
|
||||||
|
<span style="color: rgb(50, 142, 248);" >{{ form.originalName }}</span>
|
||||||
|
<!-- <el-button type="primary" link @click="handleView(scope.row)"
|
||||||
|
><el-icon><View /></el-icon>查看</el-button
|
||||||
|
> -->
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<!-- 提交组件 -->
|
||||||
|
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||||
|
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||||
|
<!-- 流程选择对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
draggable
|
||||||
|
v-model="dialogVisible.visible"
|
||||||
|
:title="dialogVisible.title"
|
||||||
|
:before-close="handleClose"
|
||||||
|
width="500"
|
||||||
|
class="rounded-lg shadow-lg"
|
||||||
|
>
|
||||||
|
<div class="p-4">
|
||||||
|
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||||
|
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||||
|
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||||
|
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||||
|
>取消</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||||
|
>确认</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Leave" lang="ts">
|
||||||
|
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||||
|
import { startWorkFlow } from '@/api/workflow/task';
|
||||||
|
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||||
|
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||||
|
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||||
|
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||||
|
import { getKnowledgeDocument } from '@/api/design/technicalStandard';
|
||||||
|
// 获取用户 store
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const loading = ref(true);
|
||||||
|
//路由参数
|
||||||
|
const routeParams = ref<Record<string, any>>({});
|
||||||
|
const flowCode = ref<string>('');
|
||||||
|
const status = ref<string>('');
|
||||||
|
const dialogVisible = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: '流程定义'
|
||||||
|
});
|
||||||
|
//提交组件
|
||||||
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||||
|
//审批记录组件
|
||||||
|
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||||
|
//按钮组件
|
||||||
|
const flowCodeOptions = [
|
||||||
|
{
|
||||||
|
value: currentProject.value?.id + '_principletechnical',
|
||||||
|
label: '设计原则审批'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: currentProject.value?.id + '_requirementstechnica',
|
||||||
|
label: '业主需求清单审批'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const leaveFormRef = ref<ElFormInstance>();
|
||||||
|
const dialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: '',
|
||||||
|
isEdit: false
|
||||||
|
});
|
||||||
|
const submitFormData = ref<StartProcessBo>({
|
||||||
|
businessId: '',
|
||||||
|
flowCode: '',
|
||||||
|
variables: {}
|
||||||
|
});
|
||||||
|
const taskVariables = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
const initFormData = {
|
||||||
|
id: undefined,
|
||||||
|
fileName:undefined,
|
||||||
|
fileUrl:undefined,
|
||||||
|
status:undefined,
|
||||||
|
originalName:undefined
|
||||||
|
};
|
||||||
|
const data = reactive({
|
||||||
|
form: { ...initFormData },
|
||||||
|
rules: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.visible = false;
|
||||||
|
flowCode.value = '';
|
||||||
|
buttonLoading.value = false;
|
||||||
|
};
|
||||||
|
const { form, rules } = toRefs(data);
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = { ...initFormData };
|
||||||
|
leaveFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取详情 */
|
||||||
|
const getInfo = () => {
|
||||||
|
loading.value = true;
|
||||||
|
buttonLoading.value = false;
|
||||||
|
nextTick(async () => {
|
||||||
|
const res = await getKnowledgeDocument(routeParams.value.id);
|
||||||
|
Object.assign(form.value, res.data);
|
||||||
|
loading.value = false;
|
||||||
|
buttonLoading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = (status1: string) => {
|
||||||
|
status.value = status1;
|
||||||
|
submit(status.value,form.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitFlow = async () => {
|
||||||
|
handleStartWorkFlow(form.value);
|
||||||
|
dialogVisible.visible = false;
|
||||||
|
};
|
||||||
|
//提交申请
|
||||||
|
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||||
|
try {
|
||||||
|
submitFormData.value.flowCode = flowCode.value;
|
||||||
|
submitFormData.value.businessId = data.id;
|
||||||
|
//流程变量
|
||||||
|
taskVariables.value = {
|
||||||
|
// leave4/5 使用的流程变量
|
||||||
|
userList: ['1', '3', '4']
|
||||||
|
};
|
||||||
|
submitFormData.value.variables = taskVariables.value;
|
||||||
|
const resp = await startWorkFlow(submitFormData.value);
|
||||||
|
if (submitVerifyRef.value) {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//审批记录
|
||||||
|
const handleApprovalRecord = () => {
|
||||||
|
approvalRecordRef.value.init(form.value.id);
|
||||||
|
};
|
||||||
|
//提交回调
|
||||||
|
const submitCallback = async () => {
|
||||||
|
await proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.go(-1);
|
||||||
|
};
|
||||||
|
//审批
|
||||||
|
const approvalVerifyOpen = async () => {
|
||||||
|
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||||
|
};
|
||||||
|
// 图纸上传成功之后 开始提交
|
||||||
|
const submit = async (status, data) => {
|
||||||
|
form.value = data;
|
||||||
|
if (status === 'draft') {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
proxy?.$modal.msgSuccess('暂存成功');
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.go(-1);
|
||||||
|
} else {
|
||||||
|
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||||
|
flowCode.value = flowCodeOptions[0].value;
|
||||||
|
dialogVisible.visible = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//说明启动过先随意穿个参数
|
||||||
|
if (flowCode.value === '' || flowCode.value === null) {
|
||||||
|
flowCode.value = 'xx';
|
||||||
|
}
|
||||||
|
await handleStartWorkFlow(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(async () => {
|
||||||
|
routeParams.value = proxy.$route.query;
|
||||||
|
reset();
|
||||||
|
loading.value = false;
|
||||||
|
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||||
|
getInfo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
/* 全局样式 */
|
||||||
|
:root {
|
||||||
|
--primary: #409eff;
|
||||||
|
--primary-light: #66b1ff;
|
||||||
|
--primary-dark: #3a8ee6;
|
||||||
|
--success: #67c23a;
|
||||||
|
--warning: #e6a23c;
|
||||||
|
--danger: #f56c6c;
|
||||||
|
--info: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单样式优化 */
|
||||||
|
.el-form-item {
|
||||||
|
.el-form-item__label {
|
||||||
|
color: #606266;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__inner,
|
||||||
|
.el-select .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s,
|
||||||
|
box-shadow 0.2s;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s,
|
||||||
|
box-shadow 0.2s;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮样式优化 */
|
||||||
|
.el-button {
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&.is-primary {
|
||||||
|
background-color: var(--primary);
|
||||||
|
border-color: var(--primary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--primary-light);
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--primary-dark);
|
||||||
|
border-color: var(--primary-dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-text {
|
||||||
|
color: var(--primary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--primary-light);
|
||||||
|
background-color: rgba(64, 158, 255, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片样式优化 */
|
||||||
|
.el-card {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
/* transform: translateY(-2px); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 对话框样式优化 */
|
||||||
|
.el-dialog {
|
||||||
|
.el-dialog__header {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
padding: 15px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__footer {
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -430,6 +430,8 @@ export default {
|
|||||||
return new Promise((resovle, reject) => {
|
return new Promise((resovle, reject) => {
|
||||||
if (this.info) {
|
if (this.info) {
|
||||||
const { cameraIndex, gateway, sn, videoIndex } = this.info;
|
const { cameraIndex, gateway, sn, videoIndex } = this.info;
|
||||||
|
console.log(this.info);
|
||||||
|
|
||||||
liveStart({
|
liveStart({
|
||||||
cameraIndex,
|
cameraIndex,
|
||||||
definition: 0,
|
definition: 0,
|
||||||
|
|||||||
266
src/views/drone/droneConfig/index.vue
Normal file
266
src/views/drone/droneConfig/index.vue
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<!-- <el-form-item label="配置名称" prop="configName">
|
||||||
|
<el-input v-model="queryParams.configName" placeholder="请输入配置名称" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item> -->
|
||||||
|
<el-form-item label="配置地址" prop="configUrl">
|
||||||
|
<el-input v-model="queryParams.configUrl" placeholder="请输入配置地址" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['drone:droneConfig:add']">新增</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['drone:droneConfig:edit']"
|
||||||
|
>修改</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['drone:droneConfig:remove']"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['drone:droneConfig:export']">导出</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="droneConfigList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="序号" align="center" type="index" width="50" />
|
||||||
|
<!-- <el-table-column label="配置名称" align="center" prop="configName" /> -->
|
||||||
|
<el-table-column label="rtmp端口" align="center" prop="rtmpPort" />
|
||||||
|
<el-table-column label="rtcp端口" align="center" prop="rtcPort" />
|
||||||
|
<el-table-column label="rtmp服务地址" align="center" prop="dockSocketUrl" />
|
||||||
|
<el-table-column label="ai识别服务地址" align="center" prop="aiUrl" />
|
||||||
|
<el-table-column label="srs服务地址" align="center" prop="srsUrl" />
|
||||||
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="修改" placement="top">
|
||||||
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['drone:droneConfig:edit']"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="删除" placement="top">
|
||||||
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['drone:droneConfig:remove']"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
|
</el-card>
|
||||||
|
<!-- 添加或修改无人机配置对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
|
<el-form ref="droneConfigFormRef" :model="form" :rules="rules" label-width="150px">
|
||||||
|
<el-form-item label="无人机服务地址" prop="dockSocketUrl">
|
||||||
|
<el-input v-model="form.dockSocketUrl" placeholder="请输入无人机服务地址" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="ai识别服务地址" prop="aiUrl">
|
||||||
|
<el-input v-model="form.aiUrl" placeholder="请输入ai识别服务地址" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="srs服务器地址" prop="srsUrl">
|
||||||
|
<el-input v-model="form.srsUrl" placeholder="请输入srs服务器地址" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="srs(rtmp服务端口)" prop="rtmpPort">
|
||||||
|
<el-input v-model="form.rtmpPort" placeholder="请输入srs(rtmp服务端口)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="srs(webrtc服务端口)" prop="rtcPort">
|
||||||
|
<el-input v-model="form.rtcPort" placeholder="请输入srs(webrtc服务端口)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="DroneConfig" lang="ts">
|
||||||
|
import { listDroneConfig, getDroneConfig, delDroneConfig, addDroneConfig, updateDroneConfig } from '@/api/drone/droneConfig';
|
||||||
|
import { DroneConfigVO, DroneConfigQuery, DroneConfigForm } from '@/api/drone/droneConfig/types';
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
const droneConfigList = ref<DroneConfigVO[]>([]);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const loading = ref(true);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const ids = ref<Array<string | number>>([]);
|
||||||
|
const single = ref(true);
|
||||||
|
const multiple = ref(true);
|
||||||
|
const total = ref(0);
|
||||||
|
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
const droneConfigFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
const dialog = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const initFormData: DroneConfigForm = {
|
||||||
|
id: undefined,
|
||||||
|
projectId: currentProject.value.id,
|
||||||
|
configName: undefined,
|
||||||
|
configUrl: undefined,
|
||||||
|
dockSocketUrl: undefined,
|
||||||
|
aiUrl: undefined,
|
||||||
|
srsUrl: undefined,
|
||||||
|
rtmpPort: undefined,
|
||||||
|
rtcPort: undefined,
|
||||||
|
remark: undefined
|
||||||
|
};
|
||||||
|
const data = reactive<PageData<DroneConfigForm, DroneConfigQuery>>({
|
||||||
|
form: { ...initFormData },
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
projectId: currentProject.value.id,
|
||||||
|
configName: undefined,
|
||||||
|
configUrl: undefined,
|
||||||
|
params: {}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }],
|
||||||
|
projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
|
||||||
|
/** 查询无人机配置列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await listDroneConfig(queryParams.value);
|
||||||
|
droneConfigList.value = res.rows;
|
||||||
|
total.value = res.total;
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = { ...initFormData };
|
||||||
|
droneConfigFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields();
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection: DroneConfigVO[]) => {
|
||||||
|
ids.value = selection.map((item) => item.id);
|
||||||
|
single.value = selection.length != 1;
|
||||||
|
multiple.value = !selection.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '添加无人机配置';
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = async (row?: DroneConfigVO) => {
|
||||||
|
reset();
|
||||||
|
const _id = row?.id || ids.value[0];
|
||||||
|
const res = await getDroneConfig(_id);
|
||||||
|
Object.assign(form.value, res.data);
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '修改无人机配置';
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
droneConfigFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true;
|
||||||
|
if (form.value.id) {
|
||||||
|
await updateDroneConfig(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
} else {
|
||||||
|
await addDroneConfig(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
}
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
dialog.visible = false;
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (row?: DroneConfigVO) => {
|
||||||
|
const _ids = row?.id || ids.value;
|
||||||
|
await proxy?.$modal.confirm('是否确认删除无人机配置编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||||
|
await delDroneConfig(_ids);
|
||||||
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
await getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = () => {
|
||||||
|
proxy?.download(
|
||||||
|
'drone/droneConfig/export',
|
||||||
|
{
|
||||||
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`droneConfig_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
form.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@ -227,8 +227,10 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<span style="color:#ff0000ab;margin-bottom: 10px;display: block;">注意:请上传doc/xls/ppt/txt/pdf/png/jpg/jpeg/zip格式文件</span>
|
<span style="color: #ff0000ab; margin-bottom: 10px; display: block"
|
||||||
</el-col><el-col :span="24">
|
>注意:请上传doc/xls/ppt/txt/pdf/png/jpg/jpeg/zip格式文件</span
|
||||||
|
> </el-col
|
||||||
|
><el-col :span="24">
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -446,6 +448,19 @@ const handleView = (row) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
form.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.detail {
|
.detail {
|
||||||
|
|||||||
@ -460,6 +460,19 @@ const handleView = (row) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
form.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.detail {
|
.detail {
|
||||||
|
|||||||
@ -447,6 +447,19 @@ const handleView = (row) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
form.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.detail {
|
.detail {
|
||||||
|
|||||||
@ -451,6 +451,19 @@ const handleView = (row) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
form.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.detail {
|
.detail {
|
||||||
|
|||||||
@ -288,12 +288,16 @@ const getList = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
console.log(queryParams.value);
|
loading.value = true;
|
||||||
|
|
||||||
const res = await listProgressCategory(queryParams.value);
|
try {
|
||||||
const data = proxy?.handleTree<ProgressCategoryVO>(res.data, 'id', 'pid');
|
const res = await listProgressCategory(queryParams.value);
|
||||||
if (data) {
|
const data = proxy?.handleTree<ProgressCategoryVO>(res.data, 'id', 'pid');
|
||||||
progressCategoryList.value = data;
|
if (data) {
|
||||||
|
progressCategoryList.value = data;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// 不管成功或失败,最后都设置为 false
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -454,12 +454,6 @@ const initOLMap = () => {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
map.on('click', (e: any) => {
|
map.on('click', (e: any) => {
|
||||||
var coordinate = e.coordinate;
|
|
||||||
|
|
||||||
// 将投影坐标转换为经纬度坐标
|
|
||||||
var lonLatCoordinate = toLonLat(coordinate);
|
|
||||||
// 输出转换后的经纬度坐标
|
|
||||||
console.log('经纬度坐标:', lonLatCoordinate);
|
|
||||||
const zoom = map.getView().getZoom();
|
const zoom = map.getView().getZoom();
|
||||||
const scale = Math.max(zoom / 10, 1); // 缩放比例,根据需要调整公式
|
const scale = Math.max(zoom / 10, 1); // 缩放比例,根据需要调整公式
|
||||||
map.forEachFeatureAtPixel(e.pixel, (feature: Feature) => {
|
map.forEachFeatureAtPixel(e.pixel, (feature: Feature) => {
|
||||||
@ -539,38 +533,6 @@ const initOLMap = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 你已有的 imageExtent 是 [minX, minY, maxX, maxY]
|
|
||||||
const createExtentBorderLayer = (extent: number[]) => {
|
|
||||||
// 构造矩形坐标,闭合成环,顺序可以是顺时针或逆时针
|
|
||||||
const coords = [
|
|
||||||
[
|
|
||||||
[extent[0], extent[1]],
|
|
||||||
[extent[0], extent[3]],
|
|
||||||
[extent[2], extent[3]],
|
|
||||||
[extent[2], extent[1]],
|
|
||||||
[extent[0], extent[1]]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
const polygonFeature = new Feature(new Polygon(coords));
|
|
||||||
|
|
||||||
polygonFeature.setStyle(
|
|
||||||
new Style({
|
|
||||||
stroke: new Stroke({
|
|
||||||
color: 'red', // 你想要的边框颜色
|
|
||||||
width: 3 // 线宽
|
|
||||||
}),
|
|
||||||
fill: null // 不填充,纯边框
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return new VectorLayer({
|
|
||||||
source: new VectorSource({
|
|
||||||
features: [polygonFeature]
|
|
||||||
})
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const highlightStyle = (name, scale) => {
|
const highlightStyle = (name, scale) => {
|
||||||
return new Style({
|
return new Style({
|
||||||
stroke: new Stroke({
|
stroke: new Stroke({
|
||||||
@ -721,7 +683,7 @@ const addPointToMap = (features: Array<any>) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//选中几何图形
|
//选中几何图形
|
||||||
const toggleFeatureHighlight = (feature: Feature, addIfNotExist = true) => {
|
const toggleFeatureHighlight = (feature: Feature) => {
|
||||||
const zoom = map.getView().getZoom();
|
const zoom = map.getView().getZoom();
|
||||||
const scale = Math.max(zoom / 10, 1);
|
const scale = Math.max(zoom / 10, 1);
|
||||||
if (feature.get('status') === '2') return;
|
if (feature.get('status') === '2') return;
|
||||||
@ -730,41 +692,35 @@ const toggleFeatureHighlight = (feature: Feature, addIfNotExist = true) => {
|
|||||||
const isHighlighted = feature.get('highlighted') === true;
|
const isHighlighted = feature.get('highlighted') === true;
|
||||||
|
|
||||||
if (isHighlighted) {
|
if (isHighlighted) {
|
||||||
|
// 如果是反选或 toggle 模式,允许取消
|
||||||
feature.setStyle(defaultStyle(feature.get('name'), scale));
|
feature.setStyle(defaultStyle(feature.get('name'), scale));
|
||||||
feature.set('highlighted', false);
|
feature.set('highlighted', false);
|
||||||
const id = feature.get('id');
|
const id = feature.get('id');
|
||||||
const idx = submitForm.value.finishedDetailIdList.indexOf(id);
|
const idx = submitForm.value.finishedDetailIdList.indexOf(id);
|
||||||
if (idx > -1) submitForm.value.finishedDetailIdList.splice(idx, 1);
|
if (idx > -1) submitForm.value.finishedDetailIdList.splice(idx, 1);
|
||||||
} else if (addIfNotExist) {
|
} else {
|
||||||
feature.setStyle(highlightStyle(feature.get('name'), scale));
|
feature.setStyle(highlightStyle(feature.get('name'), scale));
|
||||||
feature.set('highlighted', true);
|
feature.set('highlighted', true);
|
||||||
const id = feature.get('id');
|
const id = feature.get('id');
|
||||||
if (!submitForm.value.finishedDetailIdList.includes(id)) submitForm.value.finishedDetailIdList.push(id);
|
if (!submitForm.value.finishedDetailIdList.includes(id)) {
|
||||||
|
submitForm.value.finishedDetailIdList.push(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 地图初始化
|
// 地图初始化
|
||||||
initOLMap();
|
initOLMap();
|
||||||
// geoTiffLoading.value = false;
|
|
||||||
map.addLayer(sharedLayer);
|
map.addLayer(sharedLayer);
|
||||||
selector.value = new LassoSelector(map, sharedSource, (features, isInvert = false) => {
|
selector.value = new LassoSelector(map, sharedSource, (features, isInvert = false) => {
|
||||||
features.forEach((feature) => {
|
features.forEach((feature) => {
|
||||||
if (isInvert) {
|
console.log(feature.get('status'));
|
||||||
// Shift + 左键 -> 只执行取消选中
|
|
||||||
if (feature.get('highlighted') === true) {
|
toggleFeatureHighlight(feature);
|
||||||
toggleFeatureHighlight(feature, false); // 取消选中,addIfNotExist = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 普通左键 -> 只执行选中
|
|
||||||
if (feature.get('highlighted') !== true) {
|
|
||||||
toggleFeatureHighlight(feature, true); // 选中,addIfNotExist = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
enableMiddleMousePan(map);
|
// enableMiddleMousePan(map);
|
||||||
getList();
|
getList();
|
||||||
creatPoint(fromLonLat([107.13149145799198, 23.804125705140834]), 'Point', '1', '测试点1', '1');
|
creatPoint(fromLonLat([107.13149145799198, 23.804125705140834]), 'Point', '1', '测试点1', '1');
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,156 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div ref="mapContainer" class="map-container"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, onMounted } from 'vue';
|
|
||||||
import Map from 'ol/Map';
|
|
||||||
import View from 'ol/View';
|
|
||||||
import TileLayer from 'ol/layer/Tile';
|
|
||||||
import XYZ from 'ol/source/XYZ';
|
|
||||||
import TileGrid from 'ol/tilegrid/TileGrid';
|
|
||||||
import { fromLonLat, transform, transformExtent } from 'ol/proj';
|
|
||||||
import { fromUrl } from 'geotiff';
|
|
||||||
import gcoord from 'gcoord';
|
|
||||||
import ImageLayer from 'ol/layer/Image';
|
|
||||||
import Static from 'ol/source/ImageStatic';
|
|
||||||
import { Feature } from 'ol';
|
|
||||||
import { Polygon } from 'ol/geom';
|
|
||||||
import { Stroke, Style } from 'ol/style';
|
|
||||||
import VectorLayer from 'ol/layer/Vector';
|
|
||||||
import VectorSource from 'ol/source/Vector';
|
|
||||||
const mapContainer = ref<HTMLDivElement | null>(null);
|
|
||||||
|
|
||||||
// 您提供的经纬度范围(EPSG:4326)
|
|
||||||
const extent4326 = [107.13149481208748, 23.80411597354268, 107.13487254421389, 23.80801427852998];
|
|
||||||
|
|
||||||
// 计算中心点(经纬度)
|
|
||||||
const centerLon = (extent4326[0] + extent4326[2]) / 2;
|
|
||||||
const centerLat = (extent4326[1] + extent4326[3]) / 2;
|
|
||||||
|
|
||||||
// 转换 extent 到 EPSG:3857
|
|
||||||
const extent3857 = transformExtent(extent4326, 'EPSG:4326', 'EPSG:3857');
|
|
||||||
|
|
||||||
// 生成 resolutions(256像素瓦片)
|
|
||||||
const resolutions = Array.from({ length: 20 }, (_, z) => 156543.03392804097 / Math.pow(2, z));
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
// const tiff = await fromUrl('/image/clean_rgba_cleaned.tif');
|
|
||||||
// const image = await tiff.getImage();
|
|
||||||
// const width = image.getWidth();
|
|
||||||
// const height = image.getHeight();
|
|
||||||
// const bbox = image.getBoundingBox(); // [minX, minY, maxX, maxY]
|
|
||||||
// console.log('bbox', bbox);
|
|
||||||
// const rasters = await image.readRasters({ interleave: true });
|
|
||||||
// // 创建 Canvas
|
|
||||||
// const canvas = document.createElement('canvas');
|
|
||||||
// canvas.width = width;
|
|
||||||
// canvas.height = height;
|
|
||||||
// const ctx = canvas.getContext('2d')!;
|
|
||||||
// const imageData: any = ctx.createImageData(width, height);
|
|
||||||
// // 设置 RGBA 数据
|
|
||||||
// imageData.data.set(rasters); // ✅ 完整设置,不用手动循环
|
|
||||||
// ctx.putImageData(imageData, 0, 0);
|
|
||||||
// // 将 canvas 转成 Data URL 用作图层 source
|
|
||||||
// const imageUrl = canvas.toDataURL();
|
|
||||||
// // 转换为 WGS84 经纬度
|
|
||||||
// const minLonLat = transform([bbox[0], bbox[1]], 'EPSG:32648', 'EPSG:4326');
|
|
||||||
// const maxLonLat = transform([bbox[2], bbox[3]], 'EPSG:32648', 'EPSG:4326');
|
|
||||||
// console.log('minLonLat', minLonLat);
|
|
||||||
// console.log('maxLonLat', maxLonLat);
|
|
||||||
// // 转为 GCJ02(高德地图坐标系)
|
|
||||||
// const gcjMin = gcoord.transform(minLonLat as [number, number, number], gcoord.WGS84, gcoord.GCJ02);
|
|
||||||
// const gcjMax = gcoord.transform(maxLonLat as [number, number, number], gcoord.WGS84, gcoord.GCJ02);
|
|
||||||
// // 再转 EPSG:3857 供 OpenLayers 使用
|
|
||||||
// const minXY = fromLonLat(gcjMin);
|
|
||||||
// const maxXY = fromLonLat(gcjMax);
|
|
||||||
|
|
||||||
let imageExtent = [11926280.148303444, 2729254.667731837, 11926657.474014785, 2729714.281185133];
|
|
||||||
console.log('imageExtent', imageExtent);
|
|
||||||
console.log('extent3857', extent3857);
|
|
||||||
if (!mapContainer.value) return;
|
|
||||||
const tileGrid = new TileGrid({
|
|
||||||
extent: imageExtent,
|
|
||||||
origin: [-20037508.342789244, 20037508.342789244], // Web Mercator 左上角
|
|
||||||
resolutions,
|
|
||||||
tileSize: 256
|
|
||||||
});
|
|
||||||
// 高德卫星图图层 (EPSG:3857)
|
|
||||||
const gaodeLayer = new TileLayer({
|
|
||||||
source: new XYZ({
|
|
||||||
url: 'https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
|
|
||||||
maxZoom: 19,
|
|
||||||
wrapX: true
|
|
||||||
}),
|
|
||||||
opacity: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
// 自定义瓦片图层(EPSG:3857)
|
|
||||||
const customLayer = new TileLayer({
|
|
||||||
source: new XYZ({
|
|
||||||
url: 'http://192.168.110.2:8000/api/projects/3/tasks/c2e3227f-343f-48b1-88c0-1432d6eab33f/orthophoto/tiles/{z}/{x}/{y}'
|
|
||||||
// extent: imageExtent
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const layer = customLayer; // eg: TileLayer<XYZ>
|
|
||||||
const source = layer.getSource();
|
|
||||||
const projection = source?.getProjection();
|
|
||||||
|
|
||||||
console.log('图层坐标系:', projection?.getCode());
|
|
||||||
const borderLayer = createExtentBorderLayer(imageExtent);
|
|
||||||
const testLayer = createExtentBorderLayer([
|
|
||||||
...fromLonLat([107.13149481208748, 23.80411597354268]),
|
|
||||||
...fromLonLat([107.13487254421389, 23.80801427852998])
|
|
||||||
]);
|
|
||||||
// 创建地图
|
|
||||||
const map = new Map({
|
|
||||||
target: mapContainer.value,
|
|
||||||
layers: [gaodeLayer, customLayer, borderLayer, testLayer],
|
|
||||||
view: new View({
|
|
||||||
projection: 'EPSG:3857',
|
|
||||||
center: fromLonLat([centerLon, centerLat]),
|
|
||||||
zoom: 16,
|
|
||||||
minZoom: 10
|
|
||||||
// extent: extent3857 // 限制视图范围
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const createExtentBorderLayer = (extent: number[]) => {
|
|
||||||
// 构造矩形坐标,闭合成环,顺序可以是顺时针或逆时针
|
|
||||||
const coords = [
|
|
||||||
[
|
|
||||||
[extent[0], extent[1]],
|
|
||||||
[extent[0], extent[3]],
|
|
||||||
[extent[2], extent[3]],
|
|
||||||
[extent[2], extent[1]],
|
|
||||||
[extent[0], extent[1]]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
const polygonFeature = new Feature(new Polygon(coords));
|
|
||||||
|
|
||||||
polygonFeature.setStyle(
|
|
||||||
new Style({
|
|
||||||
stroke: new Stroke({
|
|
||||||
color: 'red', // 你想要的边框颜色
|
|
||||||
width: 3 // 线宽
|
|
||||||
}),
|
|
||||||
fill: null // 不填充,纯边框
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return new VectorLayer({
|
|
||||||
source: new VectorSource({
|
|
||||||
features: [polygonFeature]
|
|
||||||
})
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.map-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<el-form-item label="人员姓名" prop="userName">
|
<el-form-item label="人员姓名" prop="userName">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入人员姓名" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.userName" placeholder="请输入人员姓名" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="分包公司" prop="contractorId">
|
<el-form-item label="分包公司" prop="contractorId" v-hasPermi="['contractor:contractor:list']">
|
||||||
<el-select v-model="queryParams.contractorId" clearable placeholder="全部">
|
<el-select v-model="queryParams.contractorId" clearable placeholder="全部">
|
||||||
<el-option v-for="item in contractorOpt" :key="item.value" :label="item.label" :value="item.value" />
|
<el-option v-for="item in contractorOpt" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -40,13 +40,9 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['project:constructionUser:add']">新增 </el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['contractor:constructionUser:add']">新增 </el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['project:constructionUser:edit']">
|
|
||||||
修改
|
|
||||||
</el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
@ -54,13 +50,15 @@
|
|||||||
icon="Delete"
|
icon="Delete"
|
||||||
:disabled="multiple"
|
:disabled="multiple"
|
||||||
@click="handleDelete()"
|
@click="handleDelete()"
|
||||||
v-hasPermi="['project:constructionUser:remove']"
|
v-hasPermi="['contractor:constructionUser:remove']"
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['project:constructionUser:export']">导出 </el-button>
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['contractor:constructionUser:export']"
|
||||||
|
>导出
|
||||||
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Edit" :disabled="multiple" @click="statusDialog = true">用户状态编辑 </el-button>
|
<el-button type="warning" plain icon="Edit" :disabled="multiple" @click="statusDialog = true">用户状态编辑 </el-button>
|
||||||
@ -82,18 +80,20 @@
|
|||||||
<el-button type="success" plain>员工资料 </el-button>
|
<el-button type="success" plain>员工资料 </el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5" v-show="informationStatus">
|
<el-col :span="1.5" v-show="informationStatus">
|
||||||
<el-button type="primary" plain icon="Edit" @click="downloadTemplate">下载资料模板 </el-button>
|
<el-button type="primary" plain icon="Edit" @click="downloadTemplate" v-hasPermi="['contractor:constructionUserFile:download']"
|
||||||
|
>下载资料模板
|
||||||
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5" v-show="informationStatus">
|
<el-col :span="1.5" v-show="informationStatus">
|
||||||
<file-upload
|
<file-upload
|
||||||
v-model="filePath"
|
v-model="filePath"
|
||||||
isImportInfo
|
isImportInfo
|
||||||
:isShowTip="false"
|
:isShowTip="false"
|
||||||
uploadUrl="/project/constructionUserFile/upload/zip"
|
uploadUrl="/contractor/constructionUserFile/upload/zip"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-size="50"
|
:file-size="50"
|
||||||
>
|
>
|
||||||
<el-button type="warning" plain icon="Edit">导入员工资料 </el-button>
|
<el-button type="warning" plain icon="Edit" v-hasPermi="['contractor:constructionUserFile:upload']">导入员工资料 </el-button>
|
||||||
</file-upload>
|
</file-upload>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -165,20 +165,28 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" min-width="300">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" min-width="300">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-space wrap>
|
<el-space wrap>
|
||||||
<el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)" v-hasPermi="['project:constructionUser:query']">
|
<el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)" v-hasPermi="['contractor:constructionUser:query']">
|
||||||
详情
|
详情
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:constructionUser:edit']">
|
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['contractor:constructionUser:edit']">
|
||||||
修改
|
修改
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button link type="warning" icon="Female" @click="handlePlayCard(scope.row)"> 打卡 </el-button>
|
<el-button link type="warning" icon="Female" @click="handlePlayCard(scope.row)"> 打卡 </el-button>
|
||||||
<el-button link type="danger" icon="Avatar" @click="handleJoinBlacklist(scope.row)" v-hasPermi="['project:constructionBlacklist:add']">
|
<el-button
|
||||||
|
link
|
||||||
|
type="danger"
|
||||||
|
icon="Avatar"
|
||||||
|
@click="handleJoinBlacklist(scope.row)"
|
||||||
|
v-hasPermi="['contractor:constructionBlacklist:add']"
|
||||||
|
>
|
||||||
黑名单
|
黑名单
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- <el-button link type="primary" icon="Switch" @click="handleToggle(scope.row)"> 切换人脸 </el-button> -->
|
<!-- <el-button link type="primary" icon="Switch" @click="handleToggle(scope.row)"> 切换人脸 </el-button> -->
|
||||||
<el-button link type="primary" icon="Switch" @click="handleChange(scope.row)"> 人员迁移 </el-button>
|
<el-button link type="primary" icon="Switch" @click="handleChange(scope.row)" v-hasPermi="['contractor:constructionUser:migration']">
|
||||||
|
人员迁移
|
||||||
|
</el-button>
|
||||||
<el-button link type="primary" icon="ChatLineSquare" @click="handleExit(scope.row)"> 入退场记录 </el-button>
|
<el-button link type="primary" icon="ChatLineSquare" @click="handleExit(scope.row)"> 入退场记录 </el-button>
|
||||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:constructionUser:remove']">
|
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['contractor:constructionUser:remove']">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-tooltip content="红点:部分上传,绿点:已上传,无点:未上传" placement="right" effect="dark">
|
<el-tooltip content="红点:部分上传,绿点:已上传,无点:未上传" placement="right" effect="dark">
|
||||||
@ -194,7 +202,7 @@
|
|||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改施工人员对话框 -->
|
<!-- 添加或修改施工人员对话框 -->
|
||||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="930px" append-to-body>
|
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="930px" append-to-body>
|
||||||
<el-form ref="constructionUserFormRef" :model="form" :rules="rules" label-width="130px" :inline="true">
|
<el-form ref="constructionUserFormRef" :model="form" :rules="rules" label-width="130px" :inline="true">
|
||||||
<div class="block_box">
|
<div class="block_box">
|
||||||
<div class="msg">用户信息</div>
|
<div class="msg">用户信息</div>
|
||||||
@ -597,7 +605,7 @@ const initFormData: ConstructionUserForm = {
|
|||||||
salary: undefined,
|
salary: undefined,
|
||||||
remark: undefined
|
remark: undefined
|
||||||
};
|
};
|
||||||
const data = reactive<PageData<ConstructionUserForm, ConstructionUserQuery>>({
|
const data = reactive({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
@ -606,6 +614,7 @@ const data = reactive<PageData<ConstructionUserForm, ConstructionUserQuery>>({
|
|||||||
nickName: undefined,
|
nickName: undefined,
|
||||||
userName: undefined,
|
userName: undefined,
|
||||||
projectId: currentProject.value.id,
|
projectId: currentProject.value.id,
|
||||||
|
notUserRole: 1,
|
||||||
contractorId: undefined,
|
contractorId: undefined,
|
||||||
teamId: undefined,
|
teamId: undefined,
|
||||||
status: undefined,
|
status: undefined,
|
||||||
@ -780,6 +789,7 @@ const getContractorList = async () => {
|
|||||||
label: contractor.name
|
label: contractor.name
|
||||||
}));
|
}));
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMonth = async (e: any) => {
|
const handleMonth = async (e: any) => {
|
||||||
@ -839,6 +849,7 @@ const reset = () => {
|
|||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
|
if (contractorOpt.value.length == 1) queryParams.value.contractorId = contractorOpt.value[0].value;
|
||||||
getList();
|
getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1063,7 +1074,7 @@ const listeningProject = watch(
|
|||||||
(nid, oid) => {
|
(nid, oid) => {
|
||||||
queryParams.value.projectId = nid;
|
queryParams.value.projectId = nid;
|
||||||
form.value.projectId = nid;
|
form.value.projectId = nid;
|
||||||
getList();
|
getContractorList();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1072,7 +1083,6 @@ onUnmounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
|
||||||
getContractorList();
|
getContractorList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -25,20 +25,20 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['project:contractor:add']"> 新增 </el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['contractor:contractor:add']"> 新增 </el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['project:contractor:edit']"
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['contractor:contractor:edit']"
|
||||||
>修改
|
>修改
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['project:contractor:remove']"
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['contractor:contractor:remove']"
|
||||||
>删除
|
>删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!-- <el-col :span="1.5">
|
<!-- <el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['project:contractor:export']">导出 </el-button>
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['contractor:contractor:export']">导出 </el-button>
|
||||||
</el-col> -->
|
</el-col> -->
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -59,12 +59,14 @@
|
|||||||
<el-table-column label="管理人联系电话" align="center" prop="custodianPhone" />
|
<el-table-column label="管理人联系电话" align="center" prop="custodianPhone" />
|
||||||
<el-table-column label="备注" align="center" prop="remark" />
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180" />
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180" />
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-space wrap>
|
<el-space wrap>
|
||||||
<el-button link type="primary" icon="View" @click="handleContractorFile(scope.row)">文件</el-button>
|
<el-button link type="primary" icon="View" @click="handleContractorFile(scope.row)">文件</el-button>
|
||||||
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:contractor:edit']">修改 </el-button>
|
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['contractor:contractor:edit']"
|
||||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:contractor:remove']">
|
>修改
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['contractor:contractor:remove']">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-space>
|
</el-space>
|
||||||
@ -118,7 +120,7 @@ import { addContractor, delContractor, getContractor, listContractor, updateCont
|
|||||||
import { ContractorForm, ContractorQuery, ContractorVO } from '@/api/project/contractor/types';
|
import { ContractorForm, ContractorQuery, ContractorVO } from '@/api/project/contractor/types';
|
||||||
import ContractorFileDialog from '@/views/project/contractor/component/ContractorFileDialog.vue';
|
import ContractorFileDialog from '@/views/project/contractor/component/ContractorFileDialog.vue';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { listData } from '@/api/system/dict/data';
|
import { getDicts, listData } from '@/api/system/dict/data';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
@ -179,25 +181,19 @@ const data = reactive<PageData<ContractorForm, ContractorQuery>>({
|
|||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
/** 查询字典数据列表 */
|
/** 查询字典数据列表 */
|
||||||
const getDictList = async () => {
|
const getDictList = async () => {
|
||||||
const res = await listData({
|
const res = await getDicts('contractor_type');
|
||||||
pageNum: 1,
|
dictList.value = res.data;
|
||||||
pageSize: 10,
|
|
||||||
dictName: '',
|
|
||||||
dictType: 'contractor_type',
|
|
||||||
dictLabel: ''
|
|
||||||
});
|
|
||||||
dictList.value = res.rows;
|
|
||||||
};
|
};
|
||||||
// 分包类型
|
// 分包类型
|
||||||
const filterType=(val)=>{
|
const filterType = (val) => {
|
||||||
let label='';
|
let label = '';
|
||||||
dictList.value.forEach(item=>{
|
dictList.value.forEach((item) => {
|
||||||
if(item.dictValue==val){
|
if (item.dictValue == val) {
|
||||||
label=item.dictLabel
|
label = item.dictLabel;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return label;
|
return label;
|
||||||
}
|
};
|
||||||
/** 查询分包单位列表 */
|
/** 查询分包单位列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|||||||
@ -89,7 +89,7 @@
|
|||||||
></el-button>
|
></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="出入库" placement="top">
|
<el-tooltip content="出入库" placement="top">
|
||||||
<el-button link type="primary" icon="view" @click="handleView(scope.row)" ></el-button>
|
<el-button link type="primary" icon="view" @click="handleView(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -131,10 +131,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog draggable :title="dialogRecord.title" v-model="dialogRecord.visible" width="1500px" append-to-body>
|
<el-dialog draggable :title="dialogRecord.title" v-model="dialogRecord.visible" width="1500px" append-to-body>
|
||||||
<div>
|
<div>
|
||||||
<contractorMaterialRecord ref="contractorMaterialRecordRef" ></contractorMaterialRecord>
|
<contractorMaterialRecord ref="contractorMaterialRecordRef"></contractorMaterialRecord>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -159,7 +159,7 @@ const currentProject = computed(() => userStore.selectedProject);
|
|||||||
const contractorMaterialList = ref<ContractorMaterialVO[]>([]);
|
const contractorMaterialList = ref<ContractorMaterialVO[]>([]);
|
||||||
const buttonLoading = ref(false);
|
const buttonLoading = ref(false);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const contractorMaterialRecordRef=ref(null)
|
const contractorMaterialRecordRef = ref(null);
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
const ids = ref<Array<string | number>>([]);
|
const ids = ref<Array<string | number>>([]);
|
||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
@ -218,6 +218,7 @@ const getSubList = async () => {
|
|||||||
projectId: currentProject.value.id
|
projectId: currentProject.value.id
|
||||||
});
|
});
|
||||||
contractorList.value = res.rows;
|
contractorList.value = res.rows;
|
||||||
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 查询分包方物料列表 */
|
/** 查询分包方物料列表 */
|
||||||
@ -244,6 +245,7 @@ const reset = () => {
|
|||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
|
if (contractorList.value.length == 1) queryParams.value.contractorId = contractorList.value[0].id;
|
||||||
getList();
|
getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -310,7 +312,6 @@ const listeningProject = watch(
|
|||||||
queryParams.value.projectId = nid;
|
queryParams.value.projectId = nid;
|
||||||
form.value.projectId = nid;
|
form.value.projectId = nid;
|
||||||
getSubList();
|
getSubList();
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@ -318,13 +319,12 @@ onUnmounted(() => {
|
|||||||
});
|
});
|
||||||
const handleView = async (row: ContractorToolVO) => {
|
const handleView = async (row: ContractorToolVO) => {
|
||||||
// 打开弹框
|
// 打开弹框
|
||||||
dialogRecord.visible=true;
|
dialogRecord.visible = true;
|
||||||
dialogRecord.title=row.materialName+"-物料出入库";
|
dialogRecord.title = row.materialName + '-物料出入库';
|
||||||
await nextTick();
|
await nextTick();
|
||||||
contractorMaterialRecordRef.value.getAll(row);
|
contractorMaterialRecordRef.value.getAll(row);
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getSubList();
|
getSubList();
|
||||||
getList();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -13,8 +13,8 @@
|
|||||||
<el-input v-model="queryParams.toolName" placeholder="请输入工具名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.toolName" placeholder="请输入工具名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="工具类型" prop="toolType">
|
<el-form-item label="工具类型" prop="toolType">
|
||||||
<el-select v-model="queryParams.toolType" placeholder="请选择工具类型" clearable >
|
<el-select v-model="queryParams.toolType" placeholder="请选择工具类型" clearable>
|
||||||
<el-option v-for="dict in contractor_tool_type" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
<el-option v-for="dict in contractor_tool_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="工具型号" prop="toolModel">
|
<el-form-item label="工具型号" prop="toolModel">
|
||||||
@ -35,13 +35,23 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['project:contractorTool:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['contractor:contractorTool:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['project:contractorTool:edit']">修改</el-button>
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['contractor:contractorTool:edit']"
|
||||||
|
>修改</el-button
|
||||||
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['project:contractorTool:remove']">删除</el-button>
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
icon="Delete"
|
||||||
|
:disabled="multiple"
|
||||||
|
@click="handleDelete()"
|
||||||
|
v-hasPermi="['contractor:contractorTool:remove']"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -52,7 +62,7 @@
|
|||||||
<el-table-column label="工具名称" align="center" prop="toolName" />
|
<el-table-column label="工具名称" align="center" prop="toolName" />
|
||||||
<el-table-column label="工具类型" align="center" prop="toolType">
|
<el-table-column label="工具类型" align="center" prop="toolType">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<dict-tag :options="contractor_tool_type" :value="scope.row.toolType"/>
|
<dict-tag :options="contractor_tool_type" :value="scope.row.toolType" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="工具型号" align="center" prop="toolModel" />
|
<el-table-column label="工具型号" align="center" prop="toolModel" />
|
||||||
@ -66,13 +76,19 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:contractorTool:edit']"></el-button>
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['contractor:contractorTool:edit']"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:contractorTool:remove']"></el-button>
|
<el-button
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
icon="Delete"
|
||||||
|
@click="handleDelete(scope.row)"
|
||||||
|
v-hasPermi="['contractor:contractorTool:remove']"
|
||||||
|
></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="出入库" placement="top">
|
<el-tooltip content="出入库" placement="top">
|
||||||
<el-button link type="primary" icon="view" @click="handleView(scope.row)" ></el-button>
|
<el-button link type="primary" icon="view" @click="handleView(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -83,20 +99,15 @@
|
|||||||
<el-form ref="contractorToolFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="contractorToolFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="分包方" prop="contractorId">
|
<el-form-item label="分包方" prop="contractorId">
|
||||||
<el-select v-model="form.contractorId" filterable placeholder="请选择分包方">
|
<el-select v-model="form.contractorId" filterable placeholder="请选择分包方">
|
||||||
<el-option v-for="(item, i) of contractorList" :key="i" :label="item.name" :value="item.id"> </el-option>
|
<el-option v-for="(item, i) of contractorList" :key="i" :label="item.name" :value="item.id"> </el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="工具名称" prop="toolName">
|
<el-form-item label="工具名称" prop="toolName">
|
||||||
<el-input v-model="form.toolName" placeholder="请输入工具名称" />
|
<el-input v-model="form.toolName" placeholder="请输入工具名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="工具类型" prop="toolType">
|
<el-form-item label="工具类型" prop="toolType">
|
||||||
<el-select v-model="form.toolType" placeholder="请选择工具类型">
|
<el-select v-model="form.toolType" placeholder="请选择工具类型">
|
||||||
<el-option
|
<el-option v-for="dict in contractor_tool_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||||
v-for="dict in contractor_tool_type"
|
|
||||||
:key="dict.value"
|
|
||||||
:label="dict.label"
|
|
||||||
:value="dict.value"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="工具型号" prop="toolModel">
|
<el-form-item label="工具型号" prop="toolModel">
|
||||||
@ -106,7 +117,7 @@
|
|||||||
<file-upload v-model="form.file"/>
|
<file-upload v-model="form.file"/>
|
||||||
</el-form-item> -->
|
</el-form-item> -->
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -116,10 +127,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog draggable :title="dialogLevan.title" v-model="dialogLevan.visible" width="1500px" append-to-body>
|
<el-dialog draggable :title="dialogLevan.title" v-model="dialogLevan.visible" width="1500px" append-to-body>
|
||||||
<div>
|
<div>
|
||||||
<LevanAutbound ref="LevanAutboundRef" ></LevanAutbound>
|
<LevanAutbound ref="LevanAutboundRef"></LevanAutbound>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -127,7 +138,7 @@
|
|||||||
<script setup name="ContractorTool" lang="ts">
|
<script setup name="ContractorTool" lang="ts">
|
||||||
import { listContractorTool, getContractorTool, delContractorTool, addContractorTool, updateContractorTool } from '@/api/project/contractorTool';
|
import { listContractorTool, getContractorTool, delContractorTool, addContractorTool, updateContractorTool } from '@/api/project/contractorTool';
|
||||||
import { ContractorToolVO, ContractorToolQuery, ContractorToolForm } from '@/api/project/contractorTool/types';
|
import { ContractorToolVO, ContractorToolQuery, ContractorToolForm } from '@/api/project/contractorTool/types';
|
||||||
import { listContractor, } from '@/api/project/contractor';
|
import { listContractor } from '@/api/project/contractor';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import LevanAutbound from '@/views/project/contractorTool/component/LevanAutbound.vue';
|
import LevanAutbound from '@/views/project/contractorTool/component/LevanAutbound.vue';
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -139,13 +150,13 @@ const { contractor_tool_type } = toRefs<any>(proxy?.useDict('contractor_tool_typ
|
|||||||
const contractorToolList = ref<ContractorToolVO[]>([]);
|
const contractorToolList = ref<ContractorToolVO[]>([]);
|
||||||
const buttonLoading = ref(false);
|
const buttonLoading = ref(false);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const LevanAutboundRef=ref(null)
|
const LevanAutboundRef = ref(null);
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
const ids = ref<Array<string | number>>([]);
|
const ids = ref<Array<string | number>>([]);
|
||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const contractorList=ref([]);//分包列表
|
const contractorList = ref([]); //分包列表
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const contractorToolFormRef = ref<ElFormInstance>();
|
const contractorToolFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
@ -168,10 +179,10 @@ const initFormData: ContractorToolForm = {
|
|||||||
toolModel: undefined,
|
toolModel: undefined,
|
||||||
toolNumber: undefined,
|
toolNumber: undefined,
|
||||||
file: undefined,
|
file: undefined,
|
||||||
remark: undefined,
|
remark: undefined
|
||||||
}
|
};
|
||||||
const data = reactive<PageData<ContractorToolForm, ContractorToolQuery>>({
|
const data = reactive<PageData<ContractorToolForm, ContractorToolQuery>>({
|
||||||
form: {...initFormData},
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@ -181,30 +192,15 @@ const data = reactive<PageData<ContractorToolForm, ContractorToolQuery>>({
|
|||||||
toolType: undefined,
|
toolType: undefined,
|
||||||
toolModel: undefined,
|
toolModel: undefined,
|
||||||
toolNumber: undefined,
|
toolNumber: undefined,
|
||||||
params: {
|
params: {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
contractorId: [
|
contractorId: [{ required: true, message: '分包方不能为空', trigger: 'blur' }],
|
||||||
{ required: true, message: "分包方不能为空", trigger: "blur" },
|
toolName: [{ required: true, message: '工具名称不能为空', trigger: 'blur' }],
|
||||||
|
toolType: [{ required: true, message: '工具类型不能为空', trigger: 'blur' }],
|
||||||
],
|
toolModel: [{ required: true, message: '工具数量不能为空', trigger: 'blur' }],
|
||||||
toolName: [
|
toolNumber: [{ required: true, message: '分包方不能为空', trigger: 'blur' }]
|
||||||
{ required: true, message: "工具名称不能为空", trigger: "blur" },
|
}
|
||||||
|
|
||||||
],
|
|
||||||
toolType: [
|
|
||||||
{ required: true, message: "工具类型不能为空", trigger: "blur" },
|
|
||||||
|
|
||||||
],
|
|
||||||
toolModel: [
|
|
||||||
{ required: true, message: "工具数量不能为空", trigger: "blur" },
|
|
||||||
|
|
||||||
],
|
|
||||||
toolNumber: [
|
|
||||||
{ required: true, message: "分包方不能为空", trigger: "blur" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const { contractor_tool_record_type } = toRefs<any>(proxy?.useDict('contractor_tool_record_type'));
|
const { contractor_tool_record_type } = toRefs<any>(proxy?.useDict('contractor_tool_record_type'));
|
||||||
|
|
||||||
@ -214,9 +210,10 @@ const getSubList = async () => {
|
|||||||
const res = await listContractor({
|
const res = await listContractor({
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10000,
|
pageSize: 10000,
|
||||||
projectId: currentProject.value.id,
|
projectId: currentProject.value.id
|
||||||
});
|
});
|
||||||
contractorList.value = res.rows;
|
contractorList.value = res.rows;
|
||||||
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 查询分包方工器具列表 */
|
/** 查询分包方工器具列表 */
|
||||||
@ -226,55 +223,56 @@ const getList = async () => {
|
|||||||
contractorToolList.value = res.rows;
|
contractorToolList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = {...initFormData};
|
form.value = { ...initFormData };
|
||||||
contractorToolFormRef.value?.resetFields();
|
contractorToolFormRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
|
if (contractorList.value.length == 1) queryParams.value.contractorId = contractorList.value[0].id;
|
||||||
getList();
|
getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: ContractorToolVO[]) => {
|
const handleSelectionChange = (selection: ContractorToolVO[]) => {
|
||||||
ids.value = selection.map(item => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length != 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = !selection.length;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "添加工器具";
|
dialog.title = '添加工器具';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: ContractorToolVO) => {
|
const handleUpdate = async (row?: ContractorToolVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0]
|
const _id = row?.id || ids.value[0];
|
||||||
const res = await getContractorTool(_id);
|
const res = await getContractorTool(_id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = "修改工器具";
|
dialog.title = '修改工器具';
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
@ -282,25 +280,25 @@ const submitForm = () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateContractorTool(form.value).finally(() => buttonLoading.value = false);
|
await updateContractorTool(form.value).finally(() => (buttonLoading.value = false));
|
||||||
} else {
|
} else {
|
||||||
await addContractorTool(form.value).finally(() => buttonLoading.value = false);
|
await addContractorTool(form.value).finally(() => (buttonLoading.value = false));
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: ContractorToolVO) => {
|
const handleDelete = async (row?: ContractorToolVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除分包方工器具编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
|
await proxy?.$modal.confirm('是否确认删除分包方工器具编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||||
await delContractorTool(_ids);
|
await delContractorTool(_ids);
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
await getList();
|
await getList();
|
||||||
}
|
};
|
||||||
|
|
||||||
//监听项目id刷新数据
|
//监听项目id刷新数据
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
@ -308,8 +306,7 @@ const listeningProject = watch(
|
|||||||
(nid, oid) => {
|
(nid, oid) => {
|
||||||
queryParams.value.projectId = nid;
|
queryParams.value.projectId = nid;
|
||||||
form.value.projectId = nid;
|
form.value.projectId = nid;
|
||||||
getSubList()
|
getSubList();
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@ -317,13 +314,12 @@ onUnmounted(() => {
|
|||||||
});
|
});
|
||||||
const handleView = async (row: ContractorToolVO) => {
|
const handleView = async (row: ContractorToolVO) => {
|
||||||
// 打开弹框
|
// 打开弹框
|
||||||
dialogLevan.visible=true;
|
dialogLevan.visible = true;
|
||||||
dialogLevan.title=row.toolName+"-工器具出入库";
|
dialogLevan.title = row.toolName + '-工器具出入库';
|
||||||
await nextTick();
|
await nextTick();
|
||||||
LevanAutboundRef.value.getAll(row);
|
LevanAutboundRef.value.getAll(row);
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getSubList();
|
getSubList();
|
||||||
getList();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -45,16 +45,36 @@
|
|||||||
<el-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="expand" width="50">
|
<el-table-column type="expand" width="50">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="w187.25 ml-12.5">
|
<div class="w212.25 ml-12.5">
|
||||||
<el-button class="mb" type="primary" size="small" @click="handleOpenSetChild(row.id)" icon="plus">添加子项目</el-button>
|
<el-button class="mb" type="primary" size="small" @click="handleOpenSetChild(row.id)" icon="plus">添加子项目</el-button>
|
||||||
|
|
||||||
<el-table :data="row.children" border stripe>
|
<el-table :data="row.children" border stripe>
|
||||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||||
<el-table-column label="名称" align="center" prop="projectName" width="296" />
|
<el-table-column label="名称" align="center" prop="projectName" width="296">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-link
|
||||||
|
:type="scope.row.designId ? 'primary' : 'default'"
|
||||||
|
:disabled="!scope.row.designId"
|
||||||
|
@click="handleOpenLayer(scope.row)"
|
||||||
|
v-loading.fullscreen.lock="fullscreenLoading"
|
||||||
|
>{{ scope.row.projectName }}</el-link
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="199" />
|
<el-table-column label="创建时间" align="center" prop="createTime" width="199" />
|
||||||
<el-table-column fixed="right" align="center" label="操作" class-name="small-padding fixed-width" width="199">
|
<el-table-column fixed="right" align="center" label="操作" class-name="small-padding fixed-width" width="299">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-space>
|
<el-space>
|
||||||
|
<file-upload
|
||||||
|
:limit="1"
|
||||||
|
:fileSize="200"
|
||||||
|
:fileType="['dxf']"
|
||||||
|
v-model:model-value="dxfFile"
|
||||||
|
uploadUrl="/project/projectFile/upload/dxf"
|
||||||
|
:data="{ projectId: scope.row.id }"
|
||||||
|
>
|
||||||
|
<el-button link type="primary" icon="upload">上传DXF </el-button>
|
||||||
|
</file-upload>
|
||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
type="success"
|
type="success"
|
||||||
@ -76,7 +96,7 @@
|
|||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||||
<el-table-column label="项目名称" align="center" prop="projectName">
|
<el-table-column label="项目名称" align="center" prop="projectName">
|
||||||
<template #default="scope">
|
<!-- <template #default="scope">
|
||||||
<el-link
|
<el-link
|
||||||
:type="scope.row.designId ? 'primary' : 'default'"
|
:type="scope.row.designId ? 'primary' : 'default'"
|
||||||
:disabled="!scope.row.designId"
|
:disabled="!scope.row.designId"
|
||||||
@ -84,7 +104,7 @@
|
|||||||
v-loading.fullscreen.lock="fullscreenLoading"
|
v-loading.fullscreen.lock="fullscreenLoading"
|
||||||
>{{ scope.row.projectName }}</el-link
|
>{{ scope.row.projectName }}</el-link
|
||||||
>
|
>
|
||||||
</template>
|
</template> -->
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="项目简称" align="center" prop="shortName" />
|
<el-table-column label="项目简称" align="center" prop="shortName" />
|
||||||
<el-table-column label="状态" align="center" prop="status">
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
@ -126,16 +146,6 @@
|
|||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-space>
|
<el-space>
|
||||||
<el-button link type="primary" icon="FolderOpened" @click="handleShowUpload(scope.row)">导入安全协议书 </el-button>
|
<el-button link type="primary" icon="FolderOpened" @click="handleShowUpload(scope.row)">导入安全协议书 </el-button>
|
||||||
<file-upload
|
|
||||||
:limit="1"
|
|
||||||
:fileSize="200"
|
|
||||||
:fileType="['dxf']"
|
|
||||||
v-model:model-value="dxfFile"
|
|
||||||
uploadUrl="/project/projectFile/upload/dxf"
|
|
||||||
:data="{ projectId: scope.row.id }"
|
|
||||||
>
|
|
||||||
<el-button link type="primary" icon="upload">上传DXF </el-button>
|
|
||||||
</file-upload>
|
|
||||||
|
|
||||||
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:project:edit']">修改 </el-button>
|
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:project:edit']">修改 </el-button>
|
||||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:project:remove']">删除 </el-button>
|
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:project:remove']">删除 </el-button>
|
||||||
|
|||||||
@ -0,0 +1,188 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="block_box">
|
||||||
|
<span>用户信息</span>
|
||||||
|
<el-form label-width="130px">
|
||||||
|
<el-row :gutter="20" justify="space-around">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="人脸照">
|
||||||
|
<el-image :src="userDetail?.facePicUrl" style="width: 150px; height: 150px" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="姓名">
|
||||||
|
{{ userDetail?.userName }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话">
|
||||||
|
{{ userDetail?.phone }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="性别">
|
||||||
|
<dict-tag :options="user_sex_type" :value="userDetail?.sex" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="年龄">
|
||||||
|
{{ dayjs().diff(dayjs(userDetail?.sfzBirth), 'year') }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="民族">
|
||||||
|
{{ userDetail?.nation }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="籍贯">
|
||||||
|
{{ userDetail?.nativePlace }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="身份证号码">
|
||||||
|
{{ userDetail?.sfzNumber }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="身份证号码">
|
||||||
|
{{ userDetail?.sfzNumber }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="身份证有效开始期">
|
||||||
|
{{ dayjs(userDetail?.sfzStart).format('YYYY 年 MM 月 DD 日') }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="身份证有效结束期">
|
||||||
|
{{ dayjs(userDetail?.sfzEnd).format('YYYY 年 MM 月 DD 日') }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="身份证地址">
|
||||||
|
{{ userDetail?.sfzSite }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="block_box">
|
||||||
|
<span>银行卡</span>
|
||||||
|
<el-form label-width="130px">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="银行卡号">
|
||||||
|
{{ userDetail?.yhkNumber }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="银行开户行">
|
||||||
|
{{ userDetail?.yhkOpeningBank }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="持卡人">
|
||||||
|
{{ userDetail?.yhkCardholder }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="block_box">
|
||||||
|
<span>单位信息</span>
|
||||||
|
<el-form label-width="130px">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="施工单位">
|
||||||
|
{{ userDetail?.contractorVo?.name }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="工种">
|
||||||
|
<dict-tag :options="type_of_work" :value="userDetail?.typeOfWork" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="block_box">
|
||||||
|
<span>其他信息</span>
|
||||||
|
<el-form label-width="130px">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="班组">
|
||||||
|
{{ userDetail?.teamVo?.teamName }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="打卡状态">
|
||||||
|
<dict-tag :options="user_clock_type" :value="userDetail?.clock" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="入场时间">
|
||||||
|
{{ userDetail?.entryDate ? dayjs(userDetail?.entryDate).format('YYYY 年 MM 月 DD 日 HH:mm:ss') : '' }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="离场时间">
|
||||||
|
{{ userDetail?.leaveDate ? dayjs(userDetail?.leaveDate).format('YYYY 年 MM 月 DD 日 HH:mm:ss') : '' }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getConstructionUser } from '@/api/project/constructionUser';
|
||||||
|
import { ConstructionUserVO } from '@/api/project/constructionUser/types';
|
||||||
|
import { dayjs } from 'element-plus';
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { type_of_work, user_sex_type, user_clock_type } = toRefs<any>(proxy?.useDict('type_of_work', 'user_sex_type', 'user_clock_type'));
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
userId?: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const userDetail = ref<ConstructionUserVO>();
|
||||||
|
const getUserDetail = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await getConstructionUser(props.userId);
|
||||||
|
if (res.data && res.code === 200) {
|
||||||
|
userDetail.value = res.data;
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getUserDetail();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.userId,
|
||||||
|
(newId, oldId) => {
|
||||||
|
if (newId !== oldId) {
|
||||||
|
getUserDetail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.block_box {
|
||||||
|
border: 1px solid #9eccfa;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px 20px 20px 10px;
|
||||||
|
margin: 15px;
|
||||||
|
> span {
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1181
src/views/project/projectUser/index.vue
Normal file
1181
src/views/project/projectUser/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -33,15 +33,15 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['project:subcontract:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['contractor:subcontract:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['project:subcontract:edit']"
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['contractor:subcontract:edit']"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['project:subcontract:remove']"
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['contractor:subcontract:remove']"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -69,10 +69,16 @@
|
|||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:subcontract:edit']"></el-button>
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['contractor:subcontract:edit']"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:subcontract:remove']"></el-button>
|
<el-button
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
icon="Delete"
|
||||||
|
@click="handleDelete(scope.row)"
|
||||||
|
v-hasPermi="['contractor:subcontract:remove']"
|
||||||
|
></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -80,15 +86,15 @@
|
|||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 添加或修改分包合同对话框 -->
|
<!-- 添加或修改分包合同对话框 -->
|
||||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
<el-form ref="subcontractFormRef" :model="form" :rules="rules" label-width="110px">
|
<el-form ref="subcontractFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
<el-form-item label="分包方" prop="contractorId">
|
<el-form-item label="分包方" prop="contractorId">
|
||||||
<el-select v-model="form.contractorId" filterable placeholder="请选择分包方">
|
<el-select v-model="form.contractorId" filterable placeholder="请选择分包方">
|
||||||
<el-option v-for="(item, i) of contractorList" :key="i" :label="item.name" :value="item.id"> </el-option>
|
<el-option v-for="(item, i) of contractorList" :key="i" :label="item.name" :value="item.id"> </el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合同文件" prop="contractFileId">
|
<el-form-item label="合同文件" prop="contractFileId">
|
||||||
<file-upload fileSize="" :fileType="['doc', 'xls', 'ppt', 'txt', 'pdf', 'png', 'jpg', 'jpeg']" v-model="form.contractFileId" />
|
<file-upload :fileType="['doc', 'xls', 'ppt', 'txt', 'pdf', 'png', 'jpg', 'jpeg']" v-model="form.contractFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合同名称" prop="contractName">
|
<el-form-item label="合同名称" prop="contractName">
|
||||||
<el-input v-model="form.contractName" placeholder="请输入合同名称" />
|
<el-input v-model="form.contractName" placeholder="请输入合同名称" />
|
||||||
@ -105,8 +111,7 @@
|
|||||||
<el-input v-model="form.contractAmount" type="number" placeholder="请输入合同金额" />
|
<el-input v-model="form.contractAmount" type="number" placeholder="请输入合同金额" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合同日期" prop="contractTime">
|
<el-form-item label="合同日期" prop="contractTime">
|
||||||
<el-date-picker clearable v-model="form.contractTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择合同日期">
|
<el-date-picker clearable v-model="form.contractTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择合同日期"> </el-date-picker>
|
||||||
</el-date-picker>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||||
@ -125,7 +130,7 @@
|
|||||||
<script setup name="Subcontract" lang="ts">
|
<script setup name="Subcontract" lang="ts">
|
||||||
import { listSubcontract, getSubcontract, delSubcontract, addSubcontract, updateSubcontract } from '@/api/project/subcontract';
|
import { listSubcontract, getSubcontract, delSubcontract, addSubcontract, updateSubcontract } from '@/api/project/subcontract';
|
||||||
import { SubcontractVO, SubcontractQuery, SubcontractForm } from '@/api/project/subcontract/types';
|
import { SubcontractVO, SubcontractQuery, SubcontractForm } from '@/api/project/subcontract/types';
|
||||||
import { listContractor, } from '@/api/project/contractor';
|
import { listContractor } from '@/api/project/contractor';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -141,7 +146,7 @@ const ids = ref<Array<string | number>>([]);
|
|||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const contractorList=ref([]);//分包列表
|
const contractorList = ref([]); //分包列表
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const subcontractFormRef = ref<ElFormInstance>();
|
const subcontractFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
@ -181,7 +186,7 @@ const data = reactive<PageData<SubcontractForm, SubcontractQuery>>({
|
|||||||
contractNumber: [{ required: true, message: '合同编号不能为空', trigger: 'change' }],
|
contractNumber: [{ required: true, message: '合同编号不能为空', trigger: 'change' }],
|
||||||
contractName: [{ required: true, message: '合同名称不能为空', trigger: 'change' }],
|
contractName: [{ required: true, message: '合同名称不能为空', trigger: 'change' }],
|
||||||
contractAmount: [{ required: true, message: '合同金额不能为空', trigger: 'change' }],
|
contractAmount: [{ required: true, message: '合同金额不能为空', trigger: 'change' }],
|
||||||
contractTime: [{ required: true, message: '合同时间不能为空', trigger: 'change' }],
|
contractTime: [{ required: true, message: '合同时间不能为空', trigger: 'change' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -200,9 +205,11 @@ const getSubList = async () => {
|
|||||||
const res = await listContractor({
|
const res = await listContractor({
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10000,
|
pageSize: 10000,
|
||||||
projectId: currentProject.value.id,
|
projectId: currentProject.value.id
|
||||||
});
|
});
|
||||||
contractorList.value = res.rows;
|
contractorList.value = res.rows;
|
||||||
|
|
||||||
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
@ -220,6 +227,7 @@ const reset = () => {
|
|||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
|
if (contractorList.value.length == 1) queryParams.value.contractorId = contractorList.value[0].id;
|
||||||
getList();
|
getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -285,7 +293,7 @@ const listeningProject = watch(
|
|||||||
(nid, oid) => {
|
(nid, oid) => {
|
||||||
queryParams.value.projectId = nid;
|
queryParams.value.projectId = nid;
|
||||||
form.value.projectId = nid;
|
form.value.projectId = nid;
|
||||||
getList();
|
getSubList();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -294,6 +302,5 @@ onUnmounted(() => {
|
|||||||
});
|
});
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getSubList();
|
getSubList();
|
||||||
getList();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -23,10 +23,30 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="24" :offset="0" prop="dept">
|
||||||
|
<el-form-item label="部门">
|
||||||
|
<el-cascader
|
||||||
|
:options="postListAll"
|
||||||
|
v-model="formData.dept"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
:show-all-levels="false"
|
||||||
|
placeholder="请选择部门"
|
||||||
|
:props="{ expandTrigger: 'hover', checkStrictly: true, value: 'id', emitPath: false, multiple: true }"
|
||||||
|
@change="changeDept"
|
||||||
|
>
|
||||||
|
</el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="岗位" prop="postIdList">
|
<el-form-item label="岗位" prop="postIdList">
|
||||||
<el-select v-model="formData.postIdList" placeholder="请选择岗位" multiple>
|
<el-select v-model="formData.postIdList" placeholder="请选择岗位" multiple :disabled="!formData.dept">
|
||||||
<el-option v-for="dict in postListAll" :key="dict.postId" :label="dict.postName" :value="dict.postId" />
|
<el-option
|
||||||
|
v-for="dict in formData.postWorkList"
|
||||||
|
:key="dict.postId"
|
||||||
|
:label="dict.deptName + '/' + dict.postName"
|
||||||
|
:value="dict.postId"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -60,7 +80,7 @@ const userStore = useUserStoreHook();
|
|||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
tourTypeOptions: any[];
|
tourTypeOptions: any[];
|
||||||
risxList: any[];
|
risxList: any[];
|
||||||
postListAll: any[];
|
postListAll: any[];
|
||||||
@ -78,6 +98,7 @@ const loading = ref(false);
|
|||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
violationLevel: undefined,
|
violationLevel: undefined,
|
||||||
|
dept: undefined,
|
||||||
color: undefined,
|
color: undefined,
|
||||||
violationType: undefined as any,
|
violationType: undefined as any,
|
||||||
wxOrPc: undefined,
|
wxOrPc: undefined,
|
||||||
@ -88,6 +109,7 @@ const formData = reactive({
|
|||||||
deletedAt: undefined,
|
deletedAt: undefined,
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
riskType: '',
|
riskType: '',
|
||||||
|
postWorkList: [] as any[],
|
||||||
postIdList: [] as any[]
|
postIdList: [] as any[]
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -127,6 +149,7 @@ const resetForm = () => {
|
|||||||
violationLevel: undefined,
|
violationLevel: undefined,
|
||||||
color: undefined,
|
color: undefined,
|
||||||
violationType: undefined,
|
violationType: undefined,
|
||||||
|
dept: undefined,
|
||||||
wxOrPc: undefined,
|
wxOrPc: undefined,
|
||||||
createBy: undefined,
|
createBy: undefined,
|
||||||
updateBy: undefined,
|
updateBy: undefined,
|
||||||
@ -135,6 +158,7 @@ const resetForm = () => {
|
|||||||
deletedAt: undefined,
|
deletedAt: undefined,
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
riskType: '',
|
riskType: '',
|
||||||
|
postWorkList: [] as any[],
|
||||||
postIdList: []
|
postIdList: []
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -165,6 +189,32 @@ const onSubmit = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changeDept = (val: any) => {
|
||||||
|
formData.postWorkList = getPostVoListByIds(props.postListAll, val);
|
||||||
|
formData.postIdList = [];
|
||||||
|
console.log(formData.postWorkList, val);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getPostVoListByIds(tree: any[], idList: (string | number)[]): any[] {
|
||||||
|
const idSet = new Set(idList.map(String)); // 用于快速匹配 ID(统一为字符串比较)
|
||||||
|
const result: any[] = [];
|
||||||
|
|
||||||
|
function dfs(nodes: any[]) {
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (idSet.has(String(node.id))) {
|
||||||
|
result.push(...(node.postVoList || []));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
dfs(node.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dfs(tree);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openDialog,
|
openDialog,
|
||||||
closeDialog
|
closeDialog
|
||||||
|
|||||||
@ -25,10 +25,30 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="24" :offset="0" prop="dept">
|
||||||
|
<el-form-item label="部门">
|
||||||
|
<el-cascader
|
||||||
|
:options="postListAll"
|
||||||
|
v-model="formData.dept"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
:show-all-levels="false"
|
||||||
|
placeholder="请选择部门"
|
||||||
|
:props="{ expandTrigger: 'hover', checkStrictly: true, value: 'id', emitPath: false, multiple: true }"
|
||||||
|
@change="changeDept"
|
||||||
|
>
|
||||||
|
</el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="岗位" prop="postIdList">
|
<el-form-item label="岗位" prop="postIdList">
|
||||||
<el-select v-model="formData.postIdList" placeholder="请选择岗位" multiple>
|
<el-select v-model="formData.postIdList" placeholder="请选择岗位" multiple :disabled="!formData.dept">
|
||||||
<el-option v-for="dict in postListAll" :key="dict.postId" :label="dict.postName" :value="dict.postId" />
|
<el-option
|
||||||
|
v-for="dict in formData.postWorkList"
|
||||||
|
:key="dict.postId"
|
||||||
|
:label="dict.deptName + '/' + dict.postName"
|
||||||
|
:value="dict.postId"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -57,7 +77,7 @@ import { ElMessage, ElLoading } from 'element-plus';
|
|||||||
import { getViolationLevel, addViolationLevel, updateViolationLevel } from '@/api/safety/violationLevel';
|
import { getViolationLevel, addViolationLevel, updateViolationLevel } from '@/api/safety/violationLevel';
|
||||||
import { ViolationLevelForm, ViolationLevelVO } from '@/api/safety/violationLevel/types';
|
import { ViolationLevelForm, ViolationLevelVO } from '@/api/safety/violationLevel/types';
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
tourTypeOptions: any[];
|
tourTypeOptions: any[];
|
||||||
risxList: any[];
|
risxList: any[];
|
||||||
postListAll: any[];
|
postListAll: any[];
|
||||||
@ -75,11 +95,16 @@ const formData = reactive<
|
|||||||
risx?: string[] | string;
|
risx?: string[] | string;
|
||||||
tourType?: string[] | string;
|
tourType?: string[] | string;
|
||||||
postIdList: number[];
|
postIdList: number[];
|
||||||
|
dept: any;
|
||||||
|
postWorkList: any[];
|
||||||
}
|
}
|
||||||
>({
|
>({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
violationLevel: undefined,
|
violationLevel: undefined,
|
||||||
color: undefined,
|
color: undefined,
|
||||||
|
dept: undefined,
|
||||||
|
postWorkList: [] as any[],
|
||||||
|
|
||||||
riskType: undefined,
|
riskType: undefined,
|
||||||
createBy: undefined,
|
createBy: undefined,
|
||||||
updateBy: undefined,
|
updateBy: undefined,
|
||||||
@ -115,6 +140,8 @@ const openDialog = (row?: ViolationLevelVO) => {
|
|||||||
const data = res.data;
|
const data = res.data;
|
||||||
data.postIdList = (data.postList || []).map((item: any) => item.postId);
|
data.postIdList = (data.postList || []).map((item: any) => item.postId);
|
||||||
data.violationType = data.violationType ? (data.violationType as string).split(',') : [];
|
data.violationType = data.violationType ? (data.violationType as string).split(',') : [];
|
||||||
|
formData.dept = (data.postList || []).map((item: any) => item.deptId);
|
||||||
|
formData.postWorkList = getPostVoListByIds(props.postListAll, formData.dept);
|
||||||
Object.assign(formData, data);
|
Object.assign(formData, data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -174,11 +201,41 @@ const resetForm = () => {
|
|||||||
createdAt: undefined,
|
createdAt: undefined,
|
||||||
updatedAt: undefined,
|
updatedAt: undefined,
|
||||||
deletedAt: undefined,
|
deletedAt: undefined,
|
||||||
|
dept: undefined,
|
||||||
|
postWorkList: [],
|
||||||
|
postIdList: [],
|
||||||
|
|
||||||
risx: '',
|
risx: '',
|
||||||
posts: []
|
posts: []
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changeDept = (val: any) => {
|
||||||
|
formData.postWorkList = getPostVoListByIds(props.postListAll, val);
|
||||||
|
formData.postIdList = [];
|
||||||
|
console.log(formData.postWorkList, val);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getPostVoListByIds(tree: any[], idList: (string | number)[]): any[] {
|
||||||
|
const idSet = new Set(idList.map(String)); // 用于快速匹配 ID(统一为字符串比较)
|
||||||
|
const result: any[] = [];
|
||||||
|
|
||||||
|
function dfs(nodes: any[]) {
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (idSet.has(String(node.id))) {
|
||||||
|
result.push(...(node.postVoList || []));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
dfs(node.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dfs(tree);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openDialog,
|
openDialog,
|
||||||
closeDialog
|
closeDialog
|
||||||
|
|||||||
@ -106,7 +106,7 @@ import { ViolationLevelForm, ViolationLevelVO } from '@/api/safety/violationLeve
|
|||||||
import apiV1SystemBusViolationLevelAdd from '@/views/safety/violationLevel/component/add.vue';
|
import apiV1SystemBusViolationLevelAdd from '@/views/safety/violationLevel/component/add.vue';
|
||||||
import apiV1SystemBusViolationLevelEdit from '@/views/safety/violationLevel/component/edit.vue';
|
import apiV1SystemBusViolationLevelEdit from '@/views/safety/violationLevel/component/edit.vue';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { listPost, optionselect } from '@/api/system/post';
|
import { listPost, listTreeByProject, optionselect } from '@/api/system/post';
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
// 从 store 中获取项目列表和当前选中的项目
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
@ -145,8 +145,9 @@ const state = reactive<any>({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const postList = () => {
|
const postList = () => {
|
||||||
listPost({ pageNum: 1, pageSize: 100 }).then((res) => {
|
listTreeByProject(currentProject.value?.id).then((res) => {
|
||||||
state.postListAll = res.rows ?? [];
|
console.log('🚀 ~ listTreeByProject ~ res:', res);
|
||||||
|
state.postListAll = res.data ?? [];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,8 +158,6 @@ const initTableData = () => {
|
|||||||
const resetQuery = (formEl?: FormInstance) => {
|
const resetQuery = (formEl?: FormInstance) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.resetFields();
|
formEl.resetFields();
|
||||||
console.log(useUserStoreHook().selectedProject, currentProject.value?.id);
|
|
||||||
|
|
||||||
busViolationLevelList();
|
busViolationLevelList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,214 @@
|
|||||||
|
<template>
|
||||||
|
<!-- <el-card v-loading="loading" body-class="printMe"> -->
|
||||||
|
<div class="w75% m-a">
|
||||||
|
<div id="printMe" class="pos-relative">
|
||||||
|
<div class="resultIcon"><img :src="'../../../../../src/assets/icons/svg/' + inspectionType + '.png'" alt="" /></div>
|
||||||
|
<!-- <h2 style="text-align: center; margin-top: 5px; font-weight: bold">安全生产监督检查通知书</h2> -->
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12" style="text-align: left">填报人:{{ safetyInspectionDetail?.createByName }}</el-col>
|
||||||
|
<el-col :span="12" style="text-align: right">填报时间:{{ safetyInspectionDetail?.createTime }}</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-descriptions :column="2" border style="margin-top: 8px" label-width="160px" size="large">
|
||||||
|
<el-descriptions-item label-align="center" label="检查项目" :span="2" class-name="zebra">{{ currentProject?.name }} </el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label-align="center" label="违章类型" label-class-name="white" width="300px">
|
||||||
|
<dict-tag :options="violation_level_type" :value="safetyInspectionDetail?.violationType" />
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label-align="center" label="违章等级" label-class-name="white">
|
||||||
|
<div class="flex">
|
||||||
|
{{ safetyInspectionDetail?.levelVo.violationLevel }}:<dict-tag
|
||||||
|
:options="risk_level_type"
|
||||||
|
:value="safetyInspectionDetail?.levelVo.riskType"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label-align="center" label="检查时间" class-name="zebra"
|
||||||
|
>{{ safetyInspectionDetail?.violationTime }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label-align="center" label="检查人" class-name="zebra"
|
||||||
|
>{{ safetyInspectionDetail?.createByName }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label-align="center" label="整改人" label-class-name="white"
|
||||||
|
>{{ safetyInspectionDetail?.handlerName }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label-align="center" label="要求整改期限" label-class-name="white">
|
||||||
|
{{ safetyInspectionDetail?.disposeDeadline ? dayjs(safetyInspectionDetail?.disposeDeadline).format('YYYY - MM - DD ') : '' }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions border direction="vertical" size="large">
|
||||||
|
<el-descriptions-item label-align="center" label="巡检结果" class-name="none"></el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="2" border label-width="160px" size="large">
|
||||||
|
<el-descriptions-item label-align="center" label="内容" :span="2" label-class-name="white"
|
||||||
|
>{{ safetyInspectionDetail?.recognizeVo.description }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label-align="center" label="检查附件" :span="2" label-class-name="white">
|
||||||
|
<el-space wrap>
|
||||||
|
<!-- <div v-for="item in checkFileList" :key="item.ossId">
|
||||||
|
<span v-if="['.png', '.jpg', '.jpeg'].includes(item.fileSuffix)">
|
||||||
|
<image-preview :src="item.url" width="200px" />
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
<el-link :href="`${item.url}`" type="primary" :underline="false" target="_blank">
|
||||||
|
<span> {{ item.originalName }} </span>
|
||||||
|
</el-link>
|
||||||
|
</span>
|
||||||
|
</div> -->
|
||||||
|
<span>
|
||||||
|
<image-preview :src="safetyInspectionDetail?.recognizeVo.picture" width="200px" />
|
||||||
|
</span>
|
||||||
|
</el-space>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label-align="center" label="检查状态" :span="2" label-class-name="white">
|
||||||
|
<el-steps style="max-width: 200px" :active="Number(safetyInspectionDetail?.status)" finish-status="finish">
|
||||||
|
<el-step v-for="item in safety_inspection_type" :key="item.value" :title="item.label" />
|
||||||
|
</el-steps>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- </el-card> -->
|
||||||
|
<!-- <div class="dialog-footer">
|
||||||
|
<div class="btn-item" @click="handleExport">
|
||||||
|
<img src="../../../../assets/icons/svg/derived.png" />
|
||||||
|
<span>导出</span>
|
||||||
|
</div>
|
||||||
|
<div class="btn-item" v-print="'#printMe'">
|
||||||
|
<img src="../../../../assets/icons/svg/print.png" />
|
||||||
|
<span>打印</span>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { downLoadOss, listByIds } from '@/api/system/oss';
|
||||||
|
import { OssVO } from '@/api/system/oss/types';
|
||||||
|
import { dayjs } from 'element-plus';
|
||||||
|
import { getViolationRecord } from '@/api/safety/violationRecord';
|
||||||
|
import { ViolationRecordVO } from '@/api/safety/violationRecord/types';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
violationRecordId?: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { violation_level_type, safety_inspection_type, risk_level_type } = toRefs<any>(
|
||||||
|
proxy?.useDict('violation_level_type', 'review_type', 'reply_type', 'safety_inspection_type', 'risk_level_type')
|
||||||
|
);
|
||||||
|
// 获取用户 store
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const safetyInspectionDetail = ref<any>();
|
||||||
|
const checkFileList = ref<OssVO[]>();
|
||||||
|
const rectificationFileList = ref<OssVO[]>();
|
||||||
|
//检查状态图片
|
||||||
|
const inspectionType = computed(() => {
|
||||||
|
let imgName = 'successLogo';
|
||||||
|
if (safetyInspectionDetail.value?.status == '2') imgName = 'rectification';
|
||||||
|
if (safetyInspectionDetail.value?.reviewType == '1') imgName = 'successful';
|
||||||
|
if (safetyInspectionDetail.value?.reviewType == '2') imgName = 'failure';
|
||||||
|
console.log('🚀 ~ inspectionType ~ imgName:', imgName);
|
||||||
|
|
||||||
|
return imgName;
|
||||||
|
});
|
||||||
|
|
||||||
|
const get = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await getViolationRecord(props.violationRecordId);
|
||||||
|
if (res.data && res.code === 200) {
|
||||||
|
safetyInspectionDetail.value = res.data;
|
||||||
|
if (res.data.checkFile) {
|
||||||
|
const checkFileRes = await listByIds(res.data.checkFile.split(','));
|
||||||
|
checkFileList.value = checkFileRes.data;
|
||||||
|
}
|
||||||
|
if (res.data.rectificationFile) {
|
||||||
|
const rectificationFileRes = await listByIds(res.data.rectificationFile.split(','));
|
||||||
|
rectificationFileList.value = rectificationFileRes.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleExport = async () => {
|
||||||
|
await downLoadOss({ id: safetyInspectionDetail.value.id }, '/safety/safetyInspection/export/word', '安全生产监督检查通知书.zip');
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('🚀 ~ onMounted ~ props.safetyInspectionId:', props.violationRecordId);
|
||||||
|
get();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.violationRecordId,
|
||||||
|
(newId, oldId) => {
|
||||||
|
if (newId !== oldId) {
|
||||||
|
checkFileList.value = undefined;
|
||||||
|
rectificationFileList.value = undefined;
|
||||||
|
get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
#printMe {
|
||||||
|
padding: 15px 20px 20px 20px !important;
|
||||||
|
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.white) {
|
||||||
|
background: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.none) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.zebra) {
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
@page {
|
||||||
|
size: auto;
|
||||||
|
margin: 0mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
height: 200px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: absolute;
|
||||||
|
top: 14%;
|
||||||
|
right: 6%;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 0 10px #ddd;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 10px;
|
||||||
|
|
||||||
|
.btn-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.resultIcon {
|
||||||
|
position: absolute;
|
||||||
|
top: 100px;
|
||||||
|
right: 50px;
|
||||||
|
z-index: 10;
|
||||||
|
width: 105px;
|
||||||
|
height: 105px;
|
||||||
|
img {
|
||||||
|
width: 105px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
307
src/views/safety/violationRecord/index.vue
Normal file
307
src/views/safety/violationRecord/index.vue
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form-item label="工单号" prop="id">
|
||||||
|
<el-input v-model="queryParams.id" placeholder="请输入工单号" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="违章时间" prop="violationTime">
|
||||||
|
<el-date-picker clearable v-model="queryParams.violationTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择违章时间" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['safety:violationRecord:remove']"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="violationRecordList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="工单号" align="center" prop="id" v-if="true" />
|
||||||
|
<el-table-column label="违章等级" align="center" prop="levelVo" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
{{ scope.row.levelVo.violationLevel }}:<dict-tag :options="risk_level_type" :value="scope.row.levelVo.riskType" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="违章类型" align="center" prop="violationType">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="violation_level_type" :value="scope.row.violationType" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="违章时间" align="center" prop="violationTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ parseTime(scope.row.violationTime, '{y}-{m}-{d}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="处理人" align="center" prop="handlerName" />
|
||||||
|
<el-table-column label="整改措施" align="center" prop="measure" />
|
||||||
|
<el-table-column label="整改时间" align="center" prop="rectificationTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ parseTime(scope.row.rectificationTime, '{y}-{m}-{d}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="复查情况" align="center" prop="review" />
|
||||||
|
<el-table-column label="复查状态" align="center" prop="reviewType">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.reviewType ? (scope.row.reviewType == 1 ? '已通过' : '未通过') : '' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="复查时间" align="center" prop="reviewTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ parseTime(scope.row.reviewTime, '{y}-{m}-{d}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- <el-table-column label="处理流程类型(0仅通知 1通知整改复查)" align="center" prop="processType" /> -->
|
||||||
|
<el-table-column label="工单状态" align="center" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="safety_inspection_type" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="详情" placement="top">
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
icon="View"
|
||||||
|
@click="handleShowDialog(scope.row)"
|
||||||
|
v-hasPermi="['safety:violationRecord:view']"
|
||||||
|
></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="违章处理人" placement="top">
|
||||||
|
<el-button link type="primary" icon="User" @click="handleUpdate(scope.row)" v-hasPermi="['safety:violationRecord:edit']"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="删除" placement="top">
|
||||||
|
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['safety:violationRecord:remove']"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
|
</el-card>
|
||||||
|
<!-- 添加或修改违规记录对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
|
<el-form ref="violationRecordFormRef" :model="form" :rules="rules" label-width="90px">
|
||||||
|
<el-form-item label="违章处理人" prop="handlerId">
|
||||||
|
<el-input v-model="form.handlerId" placeholder="请输入违章处理人" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="处理期限" prop="disposeDeadline">
|
||||||
|
<el-date-picker clearable v-model="form.disposeDeadline" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择处理期限">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog title="违规记录详情" v-model="showDetailDialog" width="60vw">
|
||||||
|
<ViolationRecordDetailDialog :violation-record-id="currentViolationRecordId" />
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="ViolationRecord" lang="ts">
|
||||||
|
import { listViolationRecord, getViolationRecord, delViolationRecord, addViolationRecord, updateViolationRecord } from '@/api/safety/violationRecord';
|
||||||
|
import { ViolationRecordVO, ViolationRecordQuery, ViolationRecordForm } from '@/api/safety/violationRecord/types';
|
||||||
|
import ViolationRecordDetailDialog from './component/violationRecordDetailDialog.vue';
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { violation_level_type, risk_level_type, safety_inspection_type } = toRefs<any>(
|
||||||
|
proxy?.useDict('violation_level_type', 'risk_level_type', 'safety_inspection_type')
|
||||||
|
);
|
||||||
|
|
||||||
|
const violationRecordList = ref<ViolationRecordVO[]>([]);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const loading = ref(true);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const ids = ref<Array<string | number>>([]);
|
||||||
|
const single = ref(true);
|
||||||
|
const multiple = ref(true);
|
||||||
|
const total = ref(0);
|
||||||
|
const currentViolationRecordId = ref<string | number>(undefined);
|
||||||
|
const showDetailDialog = ref(false);
|
||||||
|
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
const violationRecordFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
const dialog = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const initFormData: ViolationRecordForm = {
|
||||||
|
id: undefined,
|
||||||
|
projectId: undefined,
|
||||||
|
levelId: undefined,
|
||||||
|
recognizeId: undefined,
|
||||||
|
violationType: undefined,
|
||||||
|
violationTime: undefined,
|
||||||
|
handlerId: undefined,
|
||||||
|
disposeDeadline: undefined,
|
||||||
|
disposeTime: undefined,
|
||||||
|
measure: undefined,
|
||||||
|
rectificationTime: undefined,
|
||||||
|
review: undefined,
|
||||||
|
reviewType: undefined,
|
||||||
|
reviewTime: undefined,
|
||||||
|
processType: undefined,
|
||||||
|
status: undefined,
|
||||||
|
remark: undefined
|
||||||
|
};
|
||||||
|
const data = reactive<PageData<ViolationRecordForm, ViolationRecordQuery>>({
|
||||||
|
form: { ...initFormData },
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
id: undefined,
|
||||||
|
projectId: undefined,
|
||||||
|
violationType: undefined,
|
||||||
|
violationTime: undefined,
|
||||||
|
handlerId: undefined,
|
||||||
|
disposeDeadline: undefined,
|
||||||
|
disposeTime: undefined,
|
||||||
|
measure: undefined,
|
||||||
|
rectificationTime: undefined,
|
||||||
|
review: undefined,
|
||||||
|
reviewType: undefined,
|
||||||
|
reviewTime: undefined,
|
||||||
|
processType: undefined,
|
||||||
|
status: undefined,
|
||||||
|
params: {}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }],
|
||||||
|
projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }],
|
||||||
|
levelId: [{ required: true, message: '违章等级id不能为空', trigger: 'blur' }],
|
||||||
|
recognizeId: [{ required: true, message: '识别记录id不能为空', trigger: 'blur' }],
|
||||||
|
processType: [{ required: true, message: '处理流程类型(0仅通知 1通知整改复查)不能为空', trigger: 'change' }],
|
||||||
|
status: [{ required: true, message: '工单状态不能为空', trigger: 'change' }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
|
||||||
|
/** 查询违规记录列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await listViolationRecord(queryParams.value);
|
||||||
|
violationRecordList.value = res.rows;
|
||||||
|
total.value = res.total;
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = { ...initFormData };
|
||||||
|
violationRecordFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields();
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection: ViolationRecordVO[]) => {
|
||||||
|
ids.value = selection.map((item) => item.id);
|
||||||
|
single.value = selection.length != 1;
|
||||||
|
multiple.value = !selection.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '添加违规记录';
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = async (row?: ViolationRecordVO) => {
|
||||||
|
reset();
|
||||||
|
form.value.id = row.id;
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '选择违章处理人';
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShowDialog = (row?: ViolationRecordVO) => {
|
||||||
|
currentViolationRecordId.value = row.id;
|
||||||
|
showDetailDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
violationRecordFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true;
|
||||||
|
await addViolationRecord(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
dialog.visible = false;
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (row?: ViolationRecordVO) => {
|
||||||
|
const _ids = row?.id || ids.value;
|
||||||
|
await proxy?.$modal.confirm('是否确认删除违规记录编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||||
|
await delViolationRecord(_ids);
|
||||||
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
await getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = () => {
|
||||||
|
proxy?.download(
|
||||||
|
'safety/violationRecord/export',
|
||||||
|
{
|
||||||
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`violationRecord_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@ -47,6 +47,11 @@
|
|||||||
>
|
>
|
||||||
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
||||||
<el-table-column prop="deptCategory" align="center" label="类别编码" width="200"></el-table-column>
|
<el-table-column prop="deptCategory" align="center" label="类别编码" width="200"></el-table-column>
|
||||||
|
<el-table-column prop="deptType" align="center" label="部门类型" width="200">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="sys_dept_type" :value="scope.row.deptType" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="orderNum" align="center" label="排序" width="200"></el-table-column>
|
<el-table-column prop="orderNum" align="center" label="排序" width="200"></el-table-column>
|
||||||
<el-table-column prop="status" align="center" label="状态" width="100">
|
<el-table-column prop="status" align="center" label="状态" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -63,7 +68,7 @@
|
|||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
|
<el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="新增" placement="top">
|
<el-tooltip content="新增" placement="top" v-if="scope.row.deptType != '2' && scope.row.deptType != '4'">
|
||||||
<el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
|
<el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
@ -75,7 +80,7 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-body width="600px">
|
<el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-body width="600px">
|
||||||
<el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="deptFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col v-if="form.parentId !== 0" :span="24">
|
<el-col v-if="form.parentId !== 0" :span="24">
|
||||||
<el-form-item label="上级部门" prop="parentId">
|
<el-form-item label="上级部门" prop="parentId">
|
||||||
@ -128,6 +133,27 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="部门类型">
|
||||||
|
<el-select v-model="form.deptType" placeholder="请选择部门类型" @change="changeProject">
|
||||||
|
<el-option v-for="dict in sys_dept_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="form.deptType == '3'">
|
||||||
|
<el-form-item label="所属项目" prop="projectId">
|
||||||
|
<el-select v-model="form.projectId" placeholder="请选择所属项目">
|
||||||
|
<el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="form.deptType == '4'">
|
||||||
|
<el-form-item label="分包单位" prop="contractorId">
|
||||||
|
<el-select v-model="form.contractorId" placeholder="请选择分包单位">
|
||||||
|
<el-option v-for="item in contractorList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -141,7 +167,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Dept" lang="ts">
|
<script setup name="Dept" lang="ts">
|
||||||
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from '@/api/system/dept';
|
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild, getDeptList, optionProjectSelect } from '@/api/system/dept';
|
||||||
import { DeptForm, DeptQuery, DeptVO } from '@/api/system/dept/types';
|
import { DeptForm, DeptQuery, DeptVO } from '@/api/system/dept/types';
|
||||||
import { UserVO } from '@/api/system/user/types';
|
import { UserVO } from '@/api/system/user/types';
|
||||||
import { listUserByDeptId } from '@/api/system/user';
|
import { listUserByDeptId } from '@/api/system/user';
|
||||||
@ -153,7 +179,7 @@ interface DeptOptionsType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
const { sys_normal_disable, sys_dept_type } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_dept_type'));
|
||||||
|
|
||||||
const deptList = ref<DeptVO[]>([]);
|
const deptList = ref<DeptVO[]>([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
@ -166,6 +192,8 @@ const dialog = reactive<DialogOption>({
|
|||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
const projectList = ref([]);
|
||||||
|
const contractorList = ref([]);
|
||||||
|
|
||||||
const deptTableRef = ref<ElTableInstance>();
|
const deptTableRef = ref<ElTableInstance>();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
@ -180,6 +208,11 @@ const initFormData: DeptForm = {
|
|||||||
leader: undefined,
|
leader: undefined,
|
||||||
phone: undefined,
|
phone: undefined,
|
||||||
email: undefined,
|
email: undefined,
|
||||||
|
isShow: undefined,
|
||||||
|
deptType: undefined,
|
||||||
|
projectId: undefined,
|
||||||
|
contractorId: undefined,
|
||||||
|
rowProjectId: undefined,
|
||||||
status: '0'
|
status: '0'
|
||||||
};
|
};
|
||||||
const initData: PageData<DeptForm, DeptQuery> = {
|
const initData: PageData<DeptForm, DeptQuery> = {
|
||||||
@ -189,7 +222,9 @@ const initData: PageData<DeptForm, DeptQuery> = {
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
deptName: undefined,
|
deptName: undefined,
|
||||||
deptCategory: undefined,
|
deptCategory: undefined,
|
||||||
status: undefined
|
status: undefined,
|
||||||
|
isShow: undefined,
|
||||||
|
deptType: undefined
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }],
|
parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }],
|
||||||
@ -230,6 +265,8 @@ const cancel = () => {
|
|||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
|
projectList.value = [];
|
||||||
|
contractorList.value = [];
|
||||||
deptFormRef.value?.resetFields();
|
deptFormRef.value?.resetFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -240,6 +277,7 @@ const handleQuery = () => {
|
|||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
|
projectList.value = [];
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -259,6 +297,7 @@ const toggleExpandAll = (data: DeptVO[], status: boolean) => {
|
|||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = async (row?: DeptVO) => {
|
const handleAdd = async (row?: DeptVO) => {
|
||||||
reset();
|
reset();
|
||||||
|
form.value.rowProjectId = row?.projectId;
|
||||||
const res = await listDept();
|
const res = await listDept();
|
||||||
const data = proxy?.handleTree<DeptOptionsType>(res.data, 'deptId');
|
const data = proxy?.handleTree<DeptOptionsType>(res.data, 'deptId');
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -274,10 +313,14 @@ const handleAdd = async (row?: DeptVO) => {
|
|||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row: DeptVO) => {
|
const handleUpdate = async (row: DeptVO) => {
|
||||||
reset();
|
reset();
|
||||||
|
form.value.rowProjectId = row?.projectId;
|
||||||
//查询当前部门所有用户
|
//查询当前部门所有用户
|
||||||
getDeptAllUser(row.deptId);
|
getDeptAllUser(row.deptId);
|
||||||
|
|
||||||
const res = await getDept(row.deptId);
|
const res = await getDept(row.deptId);
|
||||||
form.value = res.data;
|
form.value = res.data;
|
||||||
|
projectList.value = res.data.projectList;
|
||||||
|
contractorList.value = res.data.contractorList;
|
||||||
const response = await listDeptExcludeChild(row.deptId);
|
const response = await listDeptExcludeChild(row.deptId);
|
||||||
const data = proxy?.handleTree<DeptOptionsType>(response.data, 'deptId');
|
const data = proxy?.handleTree<DeptOptionsType>(response.data, 'deptId');
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -294,6 +337,17 @@ const handleUpdate = async (row: DeptVO) => {
|
|||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '修改部门';
|
dialog.title = '修改部门';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changeProject = async (val: any) => {
|
||||||
|
if (val == '3' && (!projectList.value || !projectList.value.length)) {
|
||||||
|
const res = await getDeptList();
|
||||||
|
projectList.value = res.data;
|
||||||
|
} else if (val == '4' && (!contractorList.value || !contractorList.value.length)) {
|
||||||
|
const res = await optionProjectSelect(form.value.rowProjectId);
|
||||||
|
contractorList.value = res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
deptFormRef.value?.validate(async (valid: boolean) => {
|
deptFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
|||||||
@ -35,72 +35,110 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
<el-row :gutter="20">
|
||||||
<el-card shadow="hover">
|
<!-- 部门树 -->
|
||||||
<template #header>
|
<el-col :lg="4" :xs="24" style="">
|
||||||
<el-row :gutter="10">
|
<el-card shadow="hover">
|
||||||
<el-col :span="1.5">
|
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
||||||
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
<el-tree
|
||||||
</el-col>
|
ref="deptTreeRef"
|
||||||
<el-col :span="1.5">
|
class="mt-2"
|
||||||
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">修改</el-button>
|
node-key="id"
|
||||||
</el-col>
|
:data="deptOptions"
|
||||||
<el-col :span="1.5">
|
:props="{ label: 'label', children: 'children' }"
|
||||||
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()">删除</el-button>
|
:expand-on-click-node="false"
|
||||||
</el-col>
|
:filter-node-method="filterNode"
|
||||||
<el-col :span="1.5">
|
highlight-current
|
||||||
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
default-expand-all
|
||||||
</el-col>
|
@node-click="handleNodeClick"
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
/>
|
||||||
</el-row>
|
</el-card>
|
||||||
</template>
|
</el-col>
|
||||||
|
<el-col :lg="20" :xs="24">
|
||||||
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
<el-card shadow="hover">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<template #header>
|
||||||
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
<el-row :gutter="10">
|
||||||
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
<el-col :span="1.5">
|
||||||
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
</el-col>
|
||||||
<el-table-column label="状态" align="center" width="100">
|
<el-col :span="1.5">
|
||||||
<template #default="scope">
|
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()"
|
||||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
>修改</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime">
|
|
||||||
<template #default="scope">
|
|
||||||
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column fixed="right" label="操作" width="180">
|
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
||||||
<template #default="scope">
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
|
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
||||||
</el-tooltip>
|
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
|
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
||||||
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
<el-table-column label="状态" align="center" width="100">
|
||||||
</el-tooltip>
|
<template #default="scope">
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
|
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
|
</template>
|
||||||
</el-tooltip>
|
</el-table-column>
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
|
<el-table-column label="创建时间" align="center" prop="createTime">
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
|
<template #default="scope">
|
||||||
</el-tooltip>
|
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
|
||||||
|
|
||||||
<pagination
|
<el-table-column fixed="right" label="操作" width="180">
|
||||||
v-if="total > 0"
|
<template #default="scope">
|
||||||
v-model:total="total"
|
<el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
|
||||||
v-model:page="queryParams.pageNum"
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
v-model:limit="queryParams.pageSize"
|
</el-tooltip>
|
||||||
@pagination="getList"
|
<el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
|
||||||
/>
|
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-card>
|
</el-tooltip>
|
||||||
|
<el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
|
||||||
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-if="total > 0"
|
||||||
|
v-model:total="total"
|
||||||
|
v-model:page="queryParams.pageNum"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
|
<el-form-item label="所属部门" prop="deptId">
|
||||||
|
<el-cascader
|
||||||
|
:options="deptOptions"
|
||||||
|
v-model="form.deptId"
|
||||||
|
placeholder="请选择所属部门"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
:show-all-levels="false"
|
||||||
|
:props="{ value: 'id', emitPath: false, checkStrictly: true }"
|
||||||
|
@change=""
|
||||||
|
>
|
||||||
|
</el-cascader>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
|
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -124,7 +162,7 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="菜单权限">
|
<el-form-item label="菜单权限">
|
||||||
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
|
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand(Boolean($event), 'menu')">展开/折叠</el-checkbox>
|
||||||
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
||||||
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
||||||
<el-tree
|
<el-tree
|
||||||
@ -138,6 +176,9 @@
|
|||||||
:props="{ label: 'label', children: 'children' }"
|
:props="{ label: 'label', children: 'children' }"
|
||||||
></el-tree>
|
></el-tree>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="是否为特殊角色">
|
||||||
|
<el-switch v-model="form.isSpecial" active-value="1" inactive-value="0" active-text="是" inactive-text="否"> </el-switch>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -165,7 +206,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-show="form.dataScope === '2'" label="数据权限">
|
<el-form-item v-show="form.dataScope === '2'" label="数据权限">
|
||||||
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
|
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand(Boolean($event), 'dept')">展开/折叠</el-checkbox>
|
||||||
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
||||||
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
||||||
<el-tree
|
<el-tree
|
||||||
@ -196,6 +237,8 @@ import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updat
|
|||||||
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
|
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
|
||||||
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
|
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
|
||||||
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
|
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
|
||||||
|
import api, { uploadCertList } from '@/api/system/user';
|
||||||
|
import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -214,8 +257,11 @@ const menuExpand = ref(false);
|
|||||||
const menuNodeAll = ref(false);
|
const menuNodeAll = ref(false);
|
||||||
const deptExpand = ref(true);
|
const deptExpand = ref(true);
|
||||||
const deptNodeAll = ref(false);
|
const deptNodeAll = ref(false);
|
||||||
const deptOptions = ref<DeptTreeOption[]>([]);
|
const deptOptions = ref<DeptTreeVO[]>([]);
|
||||||
|
const enabledDeptOptions = ref<DeptTreeVO[]>([]);
|
||||||
|
|
||||||
const openDataScope = ref(false);
|
const openDataScope = ref(false);
|
||||||
|
const deptName = ref('');
|
||||||
|
|
||||||
/** 数据范围选项*/
|
/** 数据范围选项*/
|
||||||
const dataScopeOptions = ref([
|
const dataScopeOptions = ref([
|
||||||
@ -232,6 +278,7 @@ const roleFormRef = ref<ElFormInstance>();
|
|||||||
const dataScopeRef = ref<ElFormInstance>();
|
const dataScopeRef = ref<ElFormInstance>();
|
||||||
const menuRef = ref<ElTreeInstance>();
|
const menuRef = ref<ElTreeInstance>();
|
||||||
const deptRef = ref<ElTreeInstance>();
|
const deptRef = ref<ElTreeInstance>();
|
||||||
|
const deptTreeRef = ref<ElTreeInstance>();
|
||||||
|
|
||||||
const initForm: RoleForm = {
|
const initForm: RoleForm = {
|
||||||
roleId: undefined,
|
roleId: undefined,
|
||||||
@ -244,6 +291,8 @@ const initForm: RoleForm = {
|
|||||||
remark: '',
|
remark: '',
|
||||||
dataScope: '1',
|
dataScope: '1',
|
||||||
menuIds: [],
|
menuIds: [],
|
||||||
|
deptId: '',
|
||||||
|
isSpecial: null,
|
||||||
deptIds: []
|
deptIds: []
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -254,6 +303,7 @@ const data = reactive<PageData<RoleForm, RoleQuery>>({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
roleName: '',
|
roleName: '',
|
||||||
roleKey: '',
|
roleKey: '',
|
||||||
|
deptId: '',
|
||||||
status: ''
|
status: ''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
@ -269,6 +319,18 @@ const dialog = reactive<DialogOption>({
|
|||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 通过条件过滤节点 */
|
||||||
|
const filterNode = (value: string, data: any) => {
|
||||||
|
if (!value) return true;
|
||||||
|
return data.label.indexOf(value) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 节点单击事件 */
|
||||||
|
const handleNodeClick = (data: DeptVO) => {
|
||||||
|
queryParams.value.deptId = data.id as string;
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询角色列表
|
* 查询角色列表
|
||||||
*/
|
*/
|
||||||
@ -293,6 +355,9 @@ const handleQuery = () => {
|
|||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', ''];
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
queryParams.value.deptId = undefined;
|
||||||
|
deptTreeRef.value?.setCurrentKey(undefined);
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
/**删除按钮操作 */
|
/**删除按钮操作 */
|
||||||
@ -496,8 +561,28 @@ const cancelDataScope = () => {
|
|||||||
form.value = { ...initForm };
|
form.value = { ...initForm };
|
||||||
openDataScope.value = false;
|
openDataScope.value = false;
|
||||||
};
|
};
|
||||||
|
/** 查询部门下拉树结构 */
|
||||||
|
const getDeptTree = async () => {
|
||||||
|
const res = await api.deptTreeSelect({ isShow: '1' });
|
||||||
|
deptOptions.value = res.data;
|
||||||
|
enabledDeptOptions.value = filterDisabledDept(res.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 过滤禁用的部门 */
|
||||||
|
const filterDisabledDept = (deptList: DeptTreeVO[]) => {
|
||||||
|
return deptList.filter((dept) => {
|
||||||
|
if (dept.disabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dept.children && dept.children.length) {
|
||||||
|
dept.children = filterDisabledDept(dept.children);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
getDeptTree(); // 初始化部门数据
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -317,7 +317,7 @@ import { RoleVO } from '@/api/system/role/types';
|
|||||||
import { PostVO } from '@/api/system/post/types';
|
import { PostVO } from '@/api/system/post/types';
|
||||||
import { globalHeaders } from '@/utils/request';
|
import { globalHeaders } from '@/utils/request';
|
||||||
import { to } from 'await-to-js';
|
import { to } from 'await-to-js';
|
||||||
import { optionselect } from '@/api/system/post';
|
import { getRoleList, optionselect } from '@/api/system/post';
|
||||||
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
|
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -430,6 +430,7 @@ const initData: PageData<UserForm, UserQuery> = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
phonenumber: [
|
phonenumber: [
|
||||||
|
{ required: true, message: '请输入手机号码', trigger: 'blur' },
|
||||||
{
|
{
|
||||||
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
||||||
message: '请输入正确的手机号码',
|
message: '请输入正确的手机号码',
|
||||||
@ -469,7 +470,7 @@ const getList = async () => {
|
|||||||
|
|
||||||
/** 查询部门下拉树结构 */
|
/** 查询部门下拉树结构 */
|
||||||
const getDeptTree = async () => {
|
const getDeptTree = async () => {
|
||||||
const res = await api.deptTreeSelect();
|
const res = await api.deptTreeSelect({ isShow: '1' });
|
||||||
deptOptions.value = res.data;
|
deptOptions.value = res.data;
|
||||||
enabledDeptOptions.value = filterDisabledDept(res.data);
|
enabledDeptOptions.value = filterDisabledDept(res.data);
|
||||||
};
|
};
|
||||||
@ -623,7 +624,6 @@ const handleAdd = async () => {
|
|||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '新增用户';
|
dialog.title = '新增用户';
|
||||||
postOptions.value = data.posts;
|
postOptions.value = data.posts;
|
||||||
roleOptions.value = data.roles;
|
|
||||||
form.value.password = initPassword.value.toString();
|
form.value.password = initPassword.value.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -638,7 +638,7 @@ const handleUpdate = async (row?: UserForm) => {
|
|||||||
postOptions.value = data.posts;
|
postOptions.value = data.posts;
|
||||||
roleOptions.value = data.roles;
|
roleOptions.value = data.roles;
|
||||||
form.value.postIds = data.postIds;
|
form.value.postIds = data.postIds;
|
||||||
form.value.roleIds = data.roleIds;
|
form.value.roleIds = data.user.roleIds;
|
||||||
form.value.password = '';
|
form.value.password = '';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -682,8 +682,11 @@ onMounted(() => {
|
|||||||
|
|
||||||
async function handleDeptChange(value: number | string) {
|
async function handleDeptChange(value: number | string) {
|
||||||
const response = await optionselect(value);
|
const response = await optionselect(value);
|
||||||
|
const roleList = await getRoleList(value);
|
||||||
|
roleOptions.value = roleList.data;
|
||||||
postOptions.value = response.data;
|
postOptions.value = response.data;
|
||||||
form.value.postIds = [];
|
form.value.postIds = [];
|
||||||
|
form.value.roleIds = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const shuttleVisible = ref(false);
|
const shuttleVisible = ref(false);
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['workflow:category:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['workflows:category:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
@ -41,13 +41,13 @@
|
|||||||
<el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['workflow:category:edit']" />
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['workflows:category:edit']" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="新增" placement="top">
|
<el-tooltip content="新增" placement="top">
|
||||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['workflow:category:add']" />
|
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['workflows:category:add']" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['workflow:category:remove']" />
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['workflows:category:remove']" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -59,7 +59,7 @@
|
|||||||
<el-tree-select
|
<el-tree-select
|
||||||
v-model="form.parentId"
|
v-model="form.parentId"
|
||||||
:data="categoryOptions"
|
:data="categoryOptions"
|
||||||
:props="{ value: 'categoryId', label: 'categoryName', children: 'children' } as any"
|
:props="{ value: 'categoryId', label: 'categoryName', children: 'children' }"
|
||||||
value-key="categoryId"
|
value-key="categoryId"
|
||||||
placeholder="请选择上级分类"
|
placeholder="请选择上级分类"
|
||||||
check-strictly
|
check-strictly
|
||||||
@ -22,10 +22,10 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button v-hasPermi="['workflow:leave:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
<el-button v-hasPermi="['workflows:leave:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button v-hasPermi="['workflow:leave:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['workflows:leave:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -60,12 +60,12 @@
|
|||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
|
<el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
|
||||||
<el-button v-hasPermi="['workflow:leave:edit']" size="small" type="primary" icon="Edit" @click="handleUpdate(scope.row)"
|
<el-button v-hasPermi="['workflows:leave:edit']" size="small" type="primary" icon="Edit" @click="handleUpdate(scope.row)"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
|
<el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
|
||||||
<el-button v-hasPermi="['workflow:leave:remove']" size="small" type="primary" icon="Delete" @click="handleDelete(scope.row)"
|
<el-button v-hasPermi="['workflows:leave:remove']" size="small" type="primary" icon="Delete" @click="handleDelete(scope.row)"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -167,7 +167,7 @@ const handleSelectionChange = (selection: LeaveVO[]) => {
|
|||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/leaveEdit/index`,
|
path: `/test/leaveEdit/index`,
|
||||||
query: {
|
query: {
|
||||||
type: 'add'
|
type: 'add'
|
||||||
}
|
}
|
||||||
@ -178,7 +178,7 @@ const handleAdd = () => {
|
|||||||
const handleUpdate = (row?: LeaveVO) => {
|
const handleUpdate = (row?: LeaveVO) => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/leaveEdit/index`,
|
path: `/test/leaveEdit/index`,
|
||||||
query: {
|
query: {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
type: 'update'
|
type: 'update'
|
||||||
@ -190,7 +190,7 @@ const handleUpdate = (row?: LeaveVO) => {
|
|||||||
const handleView = (row?: LeaveVO) => {
|
const handleView = (row?: LeaveVO) => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/leaveEdit/index`,
|
path: `/test/leaveEdit/index`,
|
||||||
query: {
|
query: {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
type: 'view'
|
type: 'view'
|
||||||
@ -30,7 +30,7 @@ const open = async (definitionId, disabled) => {
|
|||||||
};
|
};
|
||||||
/** 关闭按钮 */
|
/** 关闭按钮 */
|
||||||
function close() {
|
function close() {
|
||||||
const obj = { path: '/workflow/processDefinition', query: { activeName: proxy.$route.query.activeName } };
|
const obj = { path: '/test/test/processDefinition', query: { activeName: proxy.$route.query.activeName } };
|
||||||
proxy.$tab.closeOpenPage(obj);
|
proxy.$tab.closeOpenPage(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,13 +10,13 @@
|
|||||||
class="mt-2"
|
class="mt-2"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:data="categoryOptions"
|
:data="categoryOptions"
|
||||||
:props="{ label: 'label', children: 'children' } as any"
|
:props="{ label: 'label', children: 'children' }"
|
||||||
:expand-on-click-node="false"
|
:expand-on-click-node="false"
|
||||||
:filter-node-method="filterNode"
|
:filter-node-method="filterNode"
|
||||||
highlight-current
|
highlight-current
|
||||||
default-expand-all
|
default-expand-all
|
||||||
@node-click="handleNodeClick"
|
@node-click="handleNodeClick"
|
||||||
></el-tree>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="20" :xs="24">
|
||||||
@ -132,7 +132,7 @@
|
|||||||
<el-tree-select
|
<el-tree-select
|
||||||
v-model="selectCategory"
|
v-model="selectCategory"
|
||||||
:data="categoryOptions"
|
:data="categoryOptions"
|
||||||
:props="{ value: 'id', label: 'label', children: 'children' } as any"
|
:props="{ value: 'id', label: 'label', children: 'children' }"
|
||||||
filterable
|
filterable
|
||||||
value-key="id"
|
value-key="id"
|
||||||
:render-after-expand="false"
|
:render-after-expand="false"
|
||||||
@ -164,7 +164,7 @@
|
|||||||
<el-tree-select
|
<el-tree-select
|
||||||
v-model="form.category"
|
v-model="form.category"
|
||||||
:data="categoryOptions"
|
:data="categoryOptions"
|
||||||
:props="{ value: 'id', label: 'label', children: 'children' } as any"
|
:props="{ value: 'id', label: 'label', children: 'children' }"
|
||||||
filterable
|
filterable
|
||||||
value-key="id"
|
value-key="id"
|
||||||
:render-after-expand="false"
|
:render-after-expand="false"
|
||||||
@ -174,7 +174,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="流程编码" prop="flowCode">
|
<el-form-item label="流程编码" prop="flowCode">
|
||||||
<el-input v-model="form.flowCode" placeholder="请输入流程编码" maxlength="20" show-word-limit>
|
<el-input v-model="form.flowCode" placeholder="请输入流程编码" maxlength="20" show-word-limit>
|
||||||
<template #prepend >{{ currentProject.id }}</template>
|
<template #prepend>{{ currentProject.id }}</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="流程名称" prop="flowName">
|
<el-form-item label="流程名称" prop="flowName">
|
||||||
@ -442,7 +442,7 @@ const handlerImportDefinition = (data: UploadRequestOptions): XMLHttpRequest =>
|
|||||||
*/
|
*/
|
||||||
const design = async (row: FlowDefinitionVo) => {
|
const design = async (row: FlowDefinitionVo) => {
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
path: `/workflow/design/index`,
|
path: `/test/design/index`,
|
||||||
query: {
|
query: {
|
||||||
definitionId: row.id,
|
definitionId: row.id,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
@ -456,13 +456,10 @@ const design = async (row: FlowDefinitionVo) => {
|
|||||||
* @param row
|
* @param row
|
||||||
*/
|
*/
|
||||||
const designView = async (row: FlowDefinitionVo) => {
|
const designView = async (row: FlowDefinitionVo) => {
|
||||||
proxy.$router.push({
|
proxy.$tab.openPage(`/test/design/index`, '', {
|
||||||
path: `/workflow/design/index`,
|
definitionId: row.id,
|
||||||
query: {
|
disabled: true,
|
||||||
definitionId: row.id,
|
activeName: activeName.value
|
||||||
disabled: true,
|
|
||||||
activeName: activeName.value
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
@ -532,4 +529,17 @@ const handleCopyDef = async (row: FlowDefinitionVo) => {
|
|||||||
const handleExportDef = () => {
|
const handleExportDef = () => {
|
||||||
proxy?.download(`/workflow/definition/exportDef/${ids.value[0]}`, {}, `${flowCodeList.value[0]}.json`);
|
proxy?.download(`/workflow/definition/exportDef/${ids.value[0]}`, {}, `${flowCodeList.value[0]}.json`);
|
||||||
};
|
};
|
||||||
|
//监听项目id刷新数据
|
||||||
|
const listeningProject = watch(
|
||||||
|
() => currentProject.value.id,
|
||||||
|
(nid, oid) => {
|
||||||
|
queryParams.value.projectId = nid;
|
||||||
|
form.value.projectId = nid;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
class="mt-2"
|
class="mt-2"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:data="categoryOptions"
|
:data="categoryOptions"
|
||||||
:props="{ label: 'label', children: 'children' } as any"
|
:props="{ label: 'label', children: 'children' }"
|
||||||
:expand-on-click-node="false"
|
:expand-on-click-node="false"
|
||||||
:filter-node-method="filterNode"
|
:filter-node-method="filterNode"
|
||||||
highlight-current
|
highlight-current
|
||||||
@ -29,18 +29,20 @@ export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => {
|
|||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
ws: true,
|
ws: true,
|
||||||
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||||
},"/warm-flow-ui": {
|
},
|
||||||
target: 'http://192.168.110.119:8899',
|
'/warm-flow-ui': {
|
||||||
changeOrigin: true,
|
|
||||||
ws: true,
|
|
||||||
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
|
||||||
},"/warm-flow": {
|
|
||||||
target: 'http://192.168.110.119:8899',
|
target: 'http://192.168.110.119:8899',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
ws: true,
|
ws: true,
|
||||||
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||||
},
|
},
|
||||||
"/workflow": {
|
'/warm-flow': {
|
||||||
|
target: 'http://192.168.110.119:8899',
|
||||||
|
changeOrigin: true,
|
||||||
|
ws: true,
|
||||||
|
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||||
|
},
|
||||||
|
'/workflow': {
|
||||||
target: 'http://192.168.110.119:8899',
|
target: 'http://192.168.110.119:8899',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
ws: true,
|
ws: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user